无依赖信息查询系统(C语言+SQLite3+HTML)
一、项目核心信息
1. 项目定位
- 适用场景:简易商品信息查询、嵌入式Web学习、轻量级部署场景(无服务器依赖)
- 核心目标:实现「登录验证→商品搜索→详情查看」三大核心功能
- 项目优势:无第三方框架依赖、编译后单文件运行、SQLite3文件数据库(无需额外部署)、支持中文关键词搜索
2. 核心技术栈
- 后端:C语言(实现HTTP服务器、socket编程、数据库操作)
- 数据库:SQLite3(轻量级文件数据库,存储用户和商品数据)
- 前端:HTML(静态交互界面,登录表单、搜索表单)
- 关键技术:URL编解码(中文传输兼容)、SQL预处理(防注入)、二进制文件传输(商品图片)
3. 数据库设计
项目依赖123.db文件数据库,包含两张核心表,结构如下:
(1)用户表 users(登录验证用)
| 字段名 | 数据类型 | 约束 | 说明 |
|---|---|---|---|
| user_id | INTEGER | 自增主键 | 用户唯一标识 |
| user_name | TEXT | 非空、唯一 | 登录用户名(如zhangsan) |
| password | TEXT | 非空 | 登录密码(如123456) |
| TEXT | 可选 | 预留字段(用户邮箱) |
(2)商品表 goods(商品数据存储)
| 字段名 | 数据类型 | 约束 | 说明 |
|---|---|---|---|
| goods_id | INTEGER | 自增主键 | 商品唯一标识 |
| goods_name | TEXT | 非空 | 商品名称(如"联通100元充值卡") |
| shop_price | REAL | 非空 | 商品售价(如95.0) |
| keywords | TEXT | 可选 | 商品关键词(如"联通 充值") |
| goods_desc | TEXT | 可选 | 商品详细介绍 |
| goods_thumb | TEXT | 可选 | 缩略图路径(如"images/xxx.jpg") |
| goods_img | TEXT | 可选 | 商品大图路径 |
| original_img | TEXT | 可选 | 商品原图路径(支持放大查看) |
| goods_number | INTEGER | 非空 | 库存数量(如100) |
二、核心功能实现流程
1. 整体流程闭环
浏览器访问 → 登录页面(login.html)→ 输入账号密码 → 登录验证(查询users表)→ 搜索页面(search.html)→ 输入关键词 → 商品搜索(模糊查询goods表)→ 商品列表(动态HTML)→ 点击商品 → 详情页面(动态拼接商品信息)
2. 三大核心功能详解
(1)用户登录验证
- 触发条件:浏览器访问
http://127.0.0.1:8080,提交登录表单 - 核心逻辑:
- 解析URL中的
user和pass参数,通过urldecode处理中文/特殊字符; - 调用
check_login函数,通过SQL预处理语句查询users表,避免SQL注入; - 验证通过则返回
search.html,失败则返回错误提示页面。
- 解析URL中的
(2)商品搜索查询
- 触发条件:登录后输入关键词(如"三星""联通"),提交搜索请求
- 核心逻辑:
- 解析并解码搜索关键词,非空校验后调用
handle_search函数; - 执行SQL模糊查询(
LIKE '%' || ? || '%'),匹配goods_name字段; - 遍历结果集,动态拼接HTML片段(包含商品名称、价格、缩略图、详情链接);
- 无匹配商品时显示"共找到0个相关商品",支持重新搜索。
- 解析并解码搜索关键词,非空校验后调用
(3)商品详情查看
- 触发条件:点击商品列表中的商品名称,发起
/detail?id=xxx请求 - 核心逻辑:
- 解析URL中的商品ID,查询
goods表的完整字段; - 动态拼接详情页HTML,包含价格、库存、详细介绍、缩略图+原图(支持点击放大);
- 商品不存在时返回404页面,字段缺失时显示默认值(如"暂无详细介绍")。
- 解析URL中的商品ID,查询
三、核心代码解析
1. HTTP服务器初始化(C语言socket编程)
服务器的核心是基于TCP socket实现HTTP请求监听与响应,关键代码如下:
c
int main() {
// 1. 创建TCP套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 2. 配置服务器地址(监听8080端口,所有网卡可访问)
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(PORT), // PORT=8080
.sin_addr.s_addr = INADDR_ANY
};
// 3. 绑定端口+监听连接
bind(sfd, (struct sockaddr*)&addr, sizeof(addr));
listen(sfd, 5); // 最大排队连接数5
printf("HTTP server running at http://127.0.0.1:%d\n", PORT);
// 4. 循环接收客户端连接
while (1) {
int cfd = accept(sfd, NULL, NULL); // 阻塞等待连接
char buf[BUF_SIZE] = {0};
recv(cfd, buf, BUF_SIZE - 1, 0); // 接收HTTP请求
printf("request:\n%s\n", buf);
// 5. 路由分发(根据请求路径调用对应模块)
if (strncmp(buf, "GET /login?", 11) == 0) {
handle_login(cfd, buf); // 登录请求
} else if (strncmp(buf, "GET /search?", 12) == 0) {
handle_search_request(cfd, buf); // 搜索请求
} else if (strncmp(buf, "GET /detail?", 12) == 0) {
handle_detail_request(cfd, buf); // 详情请求
} else if (strncmp(buf, "GET /images/", 12) == 0) {
send_image(cfd, buf); // 图片请求
} else {
send_file(cfd, "login.html"); // 默认返回登录页
}
close(cfd); // 关闭当前连接
}
close(sfd);
return 0;
}
- 关键亮点:通过
strncmp解析请求路径,实现简单路由;单线程模型,适合轻量场景;无额外依赖,编译后直接运行。
2. 登录验证模块(SQL预处理防注入)
登录验证的核心是安全查询数据库,使用SQL预处理语句避免注入攻击:
c
int check_login(const char *user, const char *pass) {
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
int ret = 0;
// 打开数据库
if (sqlite3_open("123.db", &db) != SQLITE_OK) {
fprintf(stderr, "打开数据库失败:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 0;
}
// SQL预处理语句(?为参数占位符)
const char *sql = "SELECT 1 FROM users WHERE user_name = ? AND password = ?;";
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
fprintf(stderr, "SQL预处理失败:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 0;
}
// 绑定参数(避免SQL注入)
sqlite3_bind_text(stmt, 1, user, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, pass, -1, SQLITE_TRANSIENT);
// 执行查询(存在匹配用户则返回1)
if (sqlite3_step(stmt) == SQLITE_ROW) {
ret = 1;
}
// 释放资源
sqlite3_finalize(stmt);
sqlite3_close(db);
return ret;
}
- 关键亮点:使用
sqlite3_prepare_v2预处理SQL,sqlite3_bind_text绑定参数,彻底杜绝SQL注入;查询结果仅判断是否存在,提高效率。
3. 商品搜索模块(动态HTML拼接)
搜索模块需要将数据库结果动态转为HTML,核心代码如下:
c
void handle_search(int cfd, const char *key) {
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
// 打开数据库+预处理查询
sqlite3_open("123.db", &db);
const char *sql = "SELECT goods_id, goods_name, shop_price, keywords, goods_thumb FROM goods WHERE goods_name LIKE '%' || ? || '%';";
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, key, -1, SQLITE_TRANSIENT);
// 发送HTTP响应头(指定UTF-8编码,避免中文乱码)
const char *header = "HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=UTF-8\r\n\r\n";
send(cfd, header, strlen(header), 0);
send(cfd, "<h2>商品搜索结果</h2>", strlen("<h2>商品搜索结果</h2>"), 0);
// 遍历结果集,动态拼接HTML
int count = 0;
char buf[2048];
while (sqlite3_step(stmt) == SQLITE_ROW) {
count++;
int goods_id = sqlite3_column_int(stmt, 0);
const char *name = sqlite3_column_text(stmt, 1);
double price = sqlite3_column_double(stmt, 2);
const char *keywords = sqlite3_column_text(stmt, 3);
const char *img = sqlite3_column_text(stmt, 4);
// 字段默认值处理
name = name ? name : "未知商品";
keywords = keywords ? keywords : "暂无简介";
img = img ? img : "images/default.jpg";
// 拼接商品卡片HTML
snprintf(buf, sizeof(buf),
"<div style='margin:15px 0;padding:10px;border:1px solid #ccc;'>"
"<h3><a href=\"/detail?id=%d\">%s</a></h3>"
"<p>价格:¥%.2f</p>"
"<p>关键词:%s</p>"
"<img src=\"%s\" width=\"120\" height=\"100\">"
"</div><hr>",
goods_id, name, price, keywords, img);
send(cfd, buf, strlen(buf), 0);
}
// 发送商品总数
snprintf(buf, sizeof(buf), "<p>共找到 %d 个相关商品</p>", count);
send(cfd, buf, strlen(buf), 0);
sqlite3_finalize(stmt);
sqlite3_close(db);
}
- 关键亮点:动态拼接HTML,无需静态列表页;字段默认值处理,避免空指针异常;支持中文关键词,UTF-8编码兼容。
4. 图片传输模块(二进制文件发送)
商品图片需要以二进制模式读取并发送,核心代码如下:
c
void send_binary_file(int cfd, const char *filename) {
FILE *fp = fopen(filename, "rb"); // 二进制模式打开图片
if (!fp) {
const char *err = "HTTP/1.1 404 Not Found\r\n\r\n";
send(cfd, err, strlen(err), 0);
return;
}
// 发送图片响应头(指定Content-Type为image/jpeg)
const char *header = "HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\n\r\n";
send(cfd, header, strlen(header), 0);
// 循环读取并发送二进制数据
char buf[4096];
size_t n;
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
send(cfd, buf, n, 0);
}
fclose(fp);
}
- 关键亮点:二进制模式
rb读取图片,避免文件损坏;分块发送大文件,适配不同大小图片;支持JPEG格式,可扩展PNG/ICO。
四、项目部署与测试
1. 环境准备(Ubuntu/Debian)
bash
# 安装SQLite3开发库(编译依赖)
sudo apt-get update && sudo apt-get install libsqlite3-dev -y
# 安装GCC编译器(若未安装)
sudo apt-get install gcc -y
2. 项目文件结构
mall_project/
├── login_server.c # 核心服务器代码
├── login.html # 登录表单页面
├── search.html # 搜索表单页面
├── 123.db # SQLite3数据库文件
└── images/ # 商品图片目录
├── default.jpg # 默认图片
└── 200905/ # 商品图片子目录
3. 编译与运行
bash
# 编译代码(链接SQLite3库)
gcc login_server.c -o login_server -lsqlite3
# 运行服务器(监听8080端口)
./login_server
- 运行成功提示:
HTTP server running at http://127.0.0.1:8080
4. 功能测试
- 登录测试 :浏览器访问
http://127.0.0.1:8080,输入用户名zhangsan、密码123456,登录成功跳转至搜索页; - 搜索测试:输入关键词"联通",点击搜索,显示2个充值卡商品(ID27、28);
- 详情测试:点击商品名称,进入详情页,查看价格、库存、图片和详细介绍;
- 异常测试:输入错误账号密码,返回登录失败提示;搜索无结果时显示"共找到0个相关商品"。
五、项目优势与局限
1. 核心优势
- 轻量级部署:无需服务器(如Nginx、Tomcat),无需数据库服务(如MySQL),单文件+数据库+静态资源即可运行;
- 安全可靠:SQL预处理防注入,URL编解码兼容中文,输入参数校验避免异常;
- 易扩展:模块化设计,新增功能(如购物车、订单)可直接添加模块;
- 学习价值高:覆盖C语言socket编程、SQLite3操作、HTTP协议、HTML交互,适合嵌入式Web学习。
2. 局限与优化方向
- 单线程模型:同一时间仅支持一个客户端连接,可优化为多线程/进程模型;
- GET请求传输:登录和搜索参数暴露在URL中,可新增POST请求支持;
- 无状态管理:关闭浏览器后需重新登录,可添加Cookie/Session支持;
- 密码明文存储:可新增MD5加密存储,提升安全性;
- 并发性能:适合小规模使用,高并发场景需优化网络模型。