main函数
cpp
#include "fun.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int listfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == listfd)
{
perror("socket");
return 1;
}
struct sockaddr_in ser, cil;
bzero(&ser, sizeof(ser));
bzero(&cil, sizeof(cil));
ser.sin_family = AF_INET;
ser.sin_port = htons(80);
ser.sin_addr.s_addr = INADDR_ANY;
int ret = bind(listfd, (SA)&ser, sizeof(ser));
if (-1 == ret)
{
perror("bind");
return 1;
}
listen(listfd, 3);
while (1)
{
socklen_t len = sizeof(cil);
int conn = accept(listfd, (SA)&cil, &len);
if (-1 == conn)
{
perror("accept");
continue;
}
char buf[1024] = {0};
int ret = recv(conn, buf, sizeof(buf), 0);
if (ret <= 0)
{
close(conn);
continue;
}
printf("%s\n", buf);
fflush(stdout);
char *url = strtok(buf, " ");
url = strtok(NULL, " ");
char *val = strtok(NULL, "\r");
if (0 == strcmp(url, "/"))
{
send_file(conn, "./log_in.html", FILE_HTML);
}
else if (0 == strncmp(url, "/login", 6))
{
char *name = strstr(url, "username=");
name += 9;
char *pass = strchr(name, '=');
pass += 1;
char *end = strchr(name, '&');
*end = '\0';
int is_signup = (strstr(url, "action=signup") != NULL);
sqlite3 *db = NULL;
int ret = sqlite3_open("1.db", &db);
if (ret != SQLITE_OK)
{
fprintf(stderr, "sqlite3_open %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
break;
}
char *errmsg = NULL;
int flag = sql_login(db, errmsg, name, pass);
// 在 main 函数中,当用户登录成功后:
if (flag)
{
// 打开商品数据库
sqlite3 *db2 = NULL;
int ret2 = sqlite3_open("16web/123.db", &db2);
if (ret2 != SQLITE_OK)
{
fprintf(stderr, "open 123.db error: %s\n", sqlite3_errmsg(db2));
sqlite3_close(db2);
close(conn);
continue;
}
send_homepage(db2, conn);
}
else
{
if (is_signup)
{
int errmsg_signup = sql_signup(db, errmsg, name, pass);
if (errmsg_signup)
{
int flag = sql_login(db, errmsg, name, pass);
if (flag)
{
sqlite3 *db2 = NULL;
int ret2 = sqlite3_open("16web/123.db", &db2);
if (ret2 != SQLITE_OK)
{
fprintf(stderr, "open 123.db error: %s\n", sqlite3_errmsg(db2));
sqlite3_close(db2);
close(conn);
continue;
}
send_homepage(db2, conn);
}
}
else
{
send_file(conn, "./log_error.html", FILE_HTML);
}
}
else
{
send_file(conn, "./log_error.html", FILE_HTML);
}
}
sqlite3_close(db);
}
else if (0 == strncmp(url, "/search", 7))
{
char *want_find = strstr(url, "want=");
if (!want_find)
{
const char *badreq = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
send(conn, badreq, strlen(badreq), 0);
close(conn);
continue;
}
want_find += 5;
urldecode(want_find);
sqlite3 *db = NULL;
int ret = sqlite3_open("16web/123.db", &db);
if (ret != SQLITE_OK)
{
fprintf(stderr, "DB open error: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
close(conn);
continue;
}
// 使用参数化查询防止 SQL 注入(推荐)
const char *sql =
"SELECT goods_name, keywords, goods_desc, goods_thumb, goods_img FROM goods WHERE goods_name "
"LIKE ? LIMIT 1;";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
{
fprintf(stderr, "Prepare error: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
close(conn);
continue;
}
char like_pattern[512];
snprintf(like_pattern, sizeof(like_pattern), "%%%s%%", want_find);
sqlite3_bind_text(stmt, 1, like_pattern, -1, SQLITE_STATIC);
char response[8192] = {0};
int total = 0;
if (sqlite3_step(stmt) == SQLITE_ROW)
{
const char *name = (const char *)sqlite3_column_text(stmt, 0);
const char *keywords = (const char *)sqlite3_column_text(stmt, 1);
const char *desc = (const char *)sqlite3_column_text(stmt, 2);
const char *thumb = (const char *)sqlite3_column_text(stmt, 3);
const char *image = (const char *)sqlite3_column_text(stmt, 4);
total = snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html><head><meta charset=\"utf-8\"><title>%s</title></head>\n"
"<style>\n"
"body{background-image: url(background.jpg);"
"background-repeat: no-repeat;"
"background-size: cover;"
"background-position: center;"
"text-align: center;"
"margin: 0;"
"padding: 20px;"
"min-height: 100vh;"
"box-sizing: border-box;}"
" </style>\n"
"<body>\n"
"<h1>%s</h1>\n"
"<p><b>关键词:</b> %s</p>\n"
"<p><b>描述:</b> %s</p>\n",
name, name, keywords ? keywords : "", desc ? desc : "");
if (image && strlen(image) > 0)
{
char goods_img[4096];
snprintf(goods_img, sizeof(goods_img), "/16web/%s", image);
total += snprintf(response + total, sizeof(response) - total,
"<p><img src=\"%s\" alt=\"%s\" style=\"max-width:300px;\"></p>\n", goods_img, name);
}
total += snprintf(response + total, sizeof(response) - total, "</body></html>");
send(conn, response, total, 0);
}
else
{
const char *notfound = "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n<h1>未找到商品</h1>";
send(conn, notfound, strlen(notfound), 0);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
}
else if (0 == strncmp(url, "/sousuo", 7))
{
char *want_find = strstr(url, "want=");
if (!want_find)
{
const char *badreq = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
send(conn, badreq, strlen(badreq), 0);
close(conn);
continue;
}
want_find += 5; // 跳过 "want="
urldecode(want_find); // 解码 URL 编码(如 %E6%89%8B%E6%9C%BA → 手机)
// 打开数据库
sqlite3 *db = NULL;
if (sqlite3_open("16web/123.db", &db) != SQLITE_OK)
{
fprintf(stderr, "DB open error: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
close(conn);
continue;
}
// ✅ 安全的参数化查询:使用 ? 占位符
const char *sql = "SELECT goods_name, goods_thumb FROM goods WHERE goods_name LIKE ?";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
{
fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
close(conn);
continue;
}
// 构造 LIKE 模式:%用户输入%
char like_pattern[512];
snprintf(like_pattern, sizeof(like_pattern), "%%%s%%", want_find);
// 绑定参数(自动处理特殊字符,防注入)
sqlite3_bind_text(stmt, 1, like_pattern, -1, SQLITE_STATIC);
// 构建 HTML 响应
char response[65536] = {0};
int total = snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <meta charset=\"utf-8\">\n"
" <title>搜索结果</title>\n"
" <style>\n"
" .product { display: inline-block; margin: 10px; text-align: center; width: 180px; }\n"
" .product img { max-width: 160px; height: auto; border: 1px solid #ddd; }\n"
" .product p { font-size: 14px; margin: 5px 0; }\n"
"body{background-image: url(background.jpg);"
"background-repeat: no-repeat;"
"background-size: cover;"
"background-position: center;"
"text-align: center;"
"margin: 0;"
"padding: 20px;"
"min-height: 100vh;"
"box-sizing: border-box;}"
" </style>\n"
"</head>\n"
"<body>\n");
int found = 0;
// 遍历所有匹配的商品
while (sqlite3_step(stmt) == SQLITE_ROW && total < (int)sizeof(response) - 1000)
{
found = 1;
const char *name = (const char *)sqlite3_column_text(stmt, 0);
const char *thumb = (const char *)sqlite3_column_text(stmt, 1); // 第1列!
// 对商品名进行 URL 编码,用于生成安全链接
char encoded_name[2048];
strncpy(encoded_name, name, sizeof(encoded_name) - 1);
encoded_name[sizeof(encoded_name) - 1] = '\0';
urlencode(encoded_name);
total += snprintf(response + total, sizeof(response) - total,
"<div class=\"product\">\n"
" <a href=\"/search?want=%s\"><img src=\"/16web/%s\" alt=\"%s\"></a>\n"
" <p><a href=\"/search?want=%s\">%s</a></p>\n"
"</div>\n",
encoded_name, thumb ? thumb : "", name, encoded_name, name);
}
if (!found)
{
total +=
snprintf(response + total, sizeof(response) - total, "<p>未找到包含"%s"的商品。</p>", want_find);
}
total += snprintf(response + total, sizeof(response) - total, "</body></html>");
send(conn, response, total, 0);
// 清理资源
sqlite3_finalize(stmt);
sqlite3_close(db);
}
else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".jpg"))
{
send_file(conn, url + 1, FILE_JPG);
}
else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".ico"))
{
send_file(conn, "label.ico", FILE_PNG);
}
else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".png"))
{
send_file(conn, url + 1, FILE_PNG);
}
else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".bmp"))
{
send_file(conn, url + 1, FILE_BMP);
}
else if (strlen(url) > 5 && 0 == strcmp(&url[strlen(url) - 5], ".html"))
{
send_file(conn, url + 1, FILE_HTML);
}
close(conn);
}
close(listfd);
return 0;
}
fun.c
cpp
#include "fun.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
long file_size(char *file)
{
int fd = open(file, O_RDONLY);
if (-1 == fd)
{
perror("file size open error");
fprintf(stderr, "filename is %s\n", file);
return 0;
}
long size = lseek(fd, 0, SEEK_END);
return size;
}
int send_head(int conn, char *file, FILE_TYPE type)
{
char buf[256] = {0};
char *http_cmd[7] = {NULL};
http_cmd[0] = "HTTP/1.1 200 OK\r\n";
http_cmd[1] = "Date: Wed, 31 Dec 2025 01:58:31 GMT\r\n";
switch (type)
{
case FILE_HTML:
http_cmd[2] = "Content-Type: text/html;charset=utf-8\r\n";
break;
case FILE_PNG:
http_cmd[2] = "Content-Type: image/png\r\n";
break;
case FILE_JPG:
http_cmd[2] = "Content-Type: image/jpeg\r\n";
break;
case FILE_BMP:
http_cmd[2] = "Content-Type: image/bmp\r\n";
default:
http_cmd[2] = "Content-Type: text/html;charset=utf-8\r\n";
}
http_cmd[3] = buf;
sprintf(buf, "content-length: %ld\r\n", file_size(file));
http_cmd[4] = "Connection: keep-closed\r\n";
http_cmd[5] = "Server: MYWEBSer\r\n";
http_cmd[6] = "Content-Language: zh-CN\r\n\r\n";
int i = 0;
for (i = 0; i < 7; i++)
{
send(conn, http_cmd[i], strlen(http_cmd[i]), 0);
}
return 0;
}
int send_file(int conn, char *filename, FILE_TYPE type)
{
send_head(conn, filename, type);
int fd = open(filename, O_RDONLY);
if (-1 == fd)
{
perror("open");
return 1;
}
while (1)
{
char buf[4096] = {0};
int rd_ret = read(fd, buf, sizeof(buf));
if (rd_ret <= 0)
{
break;
}
send(conn, buf, rd_ret, 0);
}
close(fd);
return 0;
}
int select_login(void *arg, int col, char **result, char **title)
{
*(int *)arg = 1;
return 0;
}
int sql_login(sqlite3 *db, char *errmsg, char *name, char *pass)
{
int flag = 0;
char sql_cmd[1024] = {0};
sprintf(sql_cmd, "select * from html where id = '%s' and pass = '%s';", name, pass);
int ret = sqlite3_exec(db, sql_cmd, select_login, &flag, &errmsg);
if (ret != SQLITE_OK)
{
fprintf(stderr, "sqlite3_exec %s\n", errmsg);
sqlite3_free(errmsg);
}
return flag;
}
int sql_signup(sqlite3 *db, char *errmsg, char *name, char *pass)
{
char sql_cmd[1024] = {0};
sprintf(sql_cmd, "insert into html values('%s','%s');", name, pass);
int ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
fprintf(stderr, "sqlite3_exec %s\n", errmsg);
return 0;
sqlite3_free(errmsg);
}
return 1;
}
#define BURSIZE 2048
int hex2dec(char c)
{
if ('0' <= c && c <= '9')
{
return c - '0';
}
else if ('a' <= c && c <= 'f')
{
return c - 'a' + 10;
}
else if ('A' <= c && c <= 'F')
{
return c - 'A' + 10;
}
else
{
return -1;
}
}
char dec2hex(short int c)
{
if (0 <= c && c <= 9)
{
return c + '0';
}
else if (10 <= c && c <= 15)
{
return c + 'A' - 10;
}
else
{
return -1;
}
}
//编码一个url
void urlencode(char url[])
{
int i = 0;
int len = strlen(url);
int res_len = 0;
char res[BURSIZE];
for (i = 0; i < len; ++i)
{
char c = url[i];
if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '/' || c == '.')
{
res[res_len++] = c;
}
else
{
int j = (short int)c;
if (j < 0)
j += 256;
int i1, i0;
i1 = j / 16;
i0 = j - i1 * 16;
res[res_len++] = '%';
res[res_len++] = dec2hex(i1);
res[res_len++] = dec2hex(i0);
}
}
res[res_len] = '\0';
strcpy(url, res);
}
// 解码url
void urldecode(char url[])
{
int i = 0;
int len = strlen(url);
int res_len = 0;
char res[BURSIZE];
for (i = 0; i < len; ++i)
{
char c = url[i];
if (c != '%')
{
res[res_len++] = c;
}
else
{
char c1 = url[++i];
char c0 = url[++i];
int num = 0;
num = hex2dec(c1) * 16 + hex2dec(c0);
res[res_len++] = num;
}
}
res[res_len] = '\0';
strcpy(url, res);
}
// fun.c
int callback(void *data, int argc, char **argv, char **azColName)
{
struct SearchResult *result = (struct SearchResult *)data;
if (result->count >= 50)
{
return 0; // 超过上限,不再保存
}
struct GoodsItem *item = &result->items[result->count];
// 安全复制字段(对照 SELECT 顺序!)
strncpy(item->goods_name, argv[0] ? argv[0] : "", 512 - 1);
strncpy(item->keywords, argv[1] ? argv[1] : "", 1024 - 1);
strncpy(item->goods_thumb, argv[2] ? argv[2] : "", 1024 - 1);
strncpy(item->goods_img, argv[3] ? argv[3] : "", 1024 - 1);
strncpy(item->original_img, argv[4] ? argv[4] : "", 1024 - 1);
// 确保字符串以 \0 结尾
item->goods_name[512 - 1] = '\0';
item->keywords[1024 - 1] = '\0';
item->goods_thumb[1024 - 1] = '\0';
item->goods_img[1024 - 1] = '\0';
item->original_img[1024 - 1] = '\0';
result->count++;
return 0;
}
int send_homepage(sqlite3 *db2, int conn)
{
const char *sql = "SELECT goods_name, goods_thumb FROM goods;";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db2, sql, -1, &stmt, NULL) != SQLITE_OK)
{
fprintf(stderr, "SQL prepare error: %s\n", sqlite3_errmsg(db2));
sqlite3_close(db2);
close(conn);
}
// 构建响应
char response[65536] = {0};
int total = snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <meta charset=\"utf-8\">\n"
" <style>\n"
" .product { display: inline-block; margin: 10px; text-align: center; width: 180px; }\n"
" .product img { max-width: 160px; height: auto; border: 1px solid #ddd; }\n"
" .product p { font-size: 14px; margin: 5px 0; }\n"
"body{ background-image: url(background.jpg);"
"background-repeat: no-repeat;"
"background-size: cover;"
"background-position: center;"
"text-align: center;"
"margin: 0;"
"padding: 20px;"
"min-height: 100vh;"
"box-sizing: border-box;}"
" </style>\n"
"</head>\n"
"<body>\n"
"<form action=\"/sousuo\" method=\"GET\" class=\"search-box\">\n"
"<input type=\"text\" name=\"want\" placeholder=\"搜索\" required>\n"
"<input type=\"submit\" value=\"搜索\">\n"
"</form>\n");
while (sqlite3_step(stmt) == SQLITE_ROW) //&& total < (int)sizeof(response) - 1000)
{
const char *name = (const char *)sqlite3_column_text(stmt, 0);
const char *thumb = (const char *)sqlite3_column_text(stmt, 1);
// 使用 urlencode 对商品名进行编码,以便安全地作为 URL 参数传递
char encoded_name[2048];
strcpy(encoded_name, name);
urlencode(encoded_name);
total += sprintf(response + total,
"<div class=\"product\">\n"
" <a href=\"/search?want=%s\"><img src=\"/16web/%s\" alt=\"%s\"></a>\n"
" <p><a href=\"/search?want=%s\">%s</a></p>\n"
"</div>\n",
encoded_name, thumb, name, encoded_name, name);
}
total += sprintf(response + total,
"</body>\n"
"</html>\n");
send(conn, response, total, 0);
sqlite3_finalize(stmt);
sqlite3_close(db2);
return 0;
}
fun.h
cpp
#ifndef __FUN_H_
#define __FUN_H_
#include <sqlite3.h>
typedef struct sockaddr *(SA);
typedef enum
{
FILE_HTML,
FILE_PNG,
FILE_JPG,
FILE_BMP
} FILE_TYPE;
long file_size(char* file);
int send_head(int conn, char* file, FILE_TYPE type);
int send_file(int conn, char* filename, FILE_TYPE type);
int select_login(void *arg, int col, char **result, char **title);
int sql_login(sqlite3 *db,char *errmsg,char *name ,char *pass);
int sql_signup(sqlite3 *db,char *errmsg,char *name ,char *pass);
int hex2dec(char c);
char dec2hex(short int c);
void urlencode(char url[]);
void urldecode(char url[]);
int callback(void *data, int argc, char **argv, char **azColName);
// fun.h
struct GoodsItem {
char goods_name[512];
char keywords[1024];
char goods_thumb[1024];
char goods_img[1024];
char original_img[1024];
char goods_desc[1024];
};
struct SearchResult {
int count; // 实际找到多少个
struct GoodsItem items[50]; // 商品列表
};
int send_homepage(sqlite3 *db2, int conn);
#endif
上述为程序源码。
下面就是实现效果,
1.登录界面

2.未注册则跳转注册界面

3.注册完成后登录则进入商城界面

4.点击搜索框可搜索商品(例:搜索三星)

(点击图形也可跳转详情界面。。。。)
5.跳转搜索三星后界面

(点击图片则进入详情页)
6.进入详情页

程序到这执行基本完毕。(也可退回点击其他商品进行查看商品详情)