news 2026/5/30 14:24:23

系统编程—在线商城信息查询系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
系统编程—在线商城信息查询系统

一、项目概述

本文将介绍如何基于 C 语言实现一个简易的在线商城 Web 服务器,该服务器具备用户注册、登录、商品搜索、商品详情展示等核心功能,底层采用 SQLite3 数据库存储数据,同时解决了 SQL 注入、URL 解码等常见 Web 开发问题,可作为轻量级在线商城的基础框架。

技术栈

  • 编程语言:C 语言
  • 网络编程:Socket(TCP/IP)
  • 数据库:SQLite3
  • Web 协议:HTTP/1.1
  • 其他:文件 I/O、URL 解码、SQL 预处理语句

二、核心功能实现

1. 项目整体架构

服务器采用经典的 TCP Socket 监听 - 连接模型,端口绑定 80(HTTP 默认端口),主要处理 GET 请求,核心流程:

  1. 创建监听 Socket 并设置端口复用
  2. 循环接收客户端连接
  3. 解析 HTTP 请求行,提取请求方法和 URL
  4. 根据 URL 路由到不同业务逻辑(注册 / 登录 / 商品搜索 / 详情)
  5. 处理完成后返回 HTML / 图片等资源,关闭连接

2. 数据库基础操作

SQLite3 是轻量级嵌入式数据库,本项目使用预处理语句(sqlite3_prepare_v2 + 绑定参数)解决 SQL 注入问题,核心封装了注册和登录两个数据库操作函数。

2.1 用户注册功能
int write_register(char* name, char* pass) { sqlite3* db = NULL; int ret = sqlite3_open("123.db", &db); if (ret != SQLITE_OK) { fprintf(stderr, "sqlite3_open %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 0; } sqlite3_stmt* stmt; // 使用占位符?防止SQL注入 const char* sql = "INSERT INTO user (name, pass) VALUES (?, ?);"; ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (ret != SQLITE_OK) { fprintf(stderr, "sqlite3_prepare_v2 INSERT failed: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 0; } // 绑定参数到占位符 sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, pass, -1, SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { fprintf(stderr, "sqlite3_step INSERT failed: %s\n", sqlite3_errmsg(db)); sqlite3_finalize(stmt); sqlite3_close(db); return 0; } printf("Register success for user: %s\n", name); sqlite3_finalize(stmt); sqlite3_close(db); return 1; }
2.2 用户登录验证
int is_denglu_right(char* name, char* pass) { sqlite3* db = NULL; int ret = sqlite3_open("123.db", &db); if (ret != SQLITE_OK) { fprintf(stderr, "sqlite3_open %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 0; } int flag = 0; sqlite3_stmt* stmt; const char* sql = "SELECT * FROM user WHERE name = ? AND pass = ?;"; ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (ret != SQLITE_OK) { fprintf(stderr, "sqlite3_prepare_v2 SELECT failed: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 0; } sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, pass, -1, SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { // 查询到数据则登录成功 flag = 1; } sqlite3_finalize(stmt); sqlite3_close(db); return flag; }

3. URL 解码功能

Web 请求中 URL 参数会被编码(如空格转为 +、特殊字符转为 % XX),需解码后才能正确处理:

void url_decode(char* dest, const char* src) { char c; while (*src) { if (*src == '%') { src++; if (*src && *(src+1)) { // 解析十六进制编码 c = ( ( (*src >= 'A') ? (toupper(*src) - 'A' + 10) : (*src - '0') ) << 4 ) + ( (*(src+1) >= 'A') ? (toupper(*(src+1)) - 'A' + 10) : (*(src+1) - '0') ); *dest++ = c; src += 2; } } else if (*src == '+') { *dest++ = ' '; // +号还原为空格 src++; } else { *dest++ = *src++; } } *dest = '\0'; }

4. 商品搜索功能

解析 /search 请求中的关键词,解码后查询商品表,动态生成搜索结果 HTML:

else if (strncmp(url, "/search?", 8) == 0) { char* name_ptr = strstr(url, "username="); if (name_ptr) { char encoded_name[128] = {0}; char decoded_name[128] = {0}; sscanf(name_ptr, "username=%s", encoded_name); url_decode(decoded_name, encoded_name); // 解码搜索关键词 FILE* fp = fopen("05.html", "w"); if (NULL == fp) { perror("fopen 05.html"); close(conn); continue; } // 生成搜索结果HTML头部 fprintf(fp, "<!DOCTYPE html>\n<html>\n<head>\n<meta charset='utf-8'>\n<title>Search Results</title>\n</head>\n<body>\n"); fprintf(fp, "<h1>Search results for: %s</h1>\n", decoded_name); sqlite3* db = NULL; if (sqlite3_open("123.db", &db) == SQLITE_OK) { char* errmsg = NULL; char sql_cmd[512] = {0}; // 模糊查询商品名称 sprintf(sql_cmd, "select goods_id,goods_name,goods_img from goods where goods_name like '%s%%';", decoded_name); ret = sqlite3_exec(db, sql_cmd, detail3, fp, &errmsg); if (ret != SQLITE_OK) { fprintf(stderr, "exec search [%s] msg:%s\n", sql_cmd, errmsg); sqlite3_free(errmsg); } sqlite3_close(db); } fprintf(fp, "</body>\n</html>"); fclose(fp); send_file(conn, "./05.html", FILE_HTML); } else { send_file(conn, "./03.html", FILE_HTML); } }

5. HTTP 响应封装

封装了文件大小计算、响应头发送、文件发送函数,支持 HTML/PNG/JPG/ICO 等类型文件:

// 计算文件大小 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 -1; } long size = lseek(fd, 0, SEEK_END); close(fd); return size; } // 发送HTTP响应头 int send_head(int conn, char* file, FILE_TYPE type) { char buf[256] = {0}; long size = file_size(file); if (size < 0) return -1; char* http_cmd[7] = {NULL}; http_cmd[0] = "HTTP/1.1 200 OK\r\n"; http_cmd[1] = "Date: Tue, 15 Nov 1994 08:12: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_ICO: http_cmd[2] = "Content-Type: image/x-icon\r\n"; break; default: http_cmd[2] = "Content-Type: text/html;charset=utf-8\r\n"; } http_cmd[3] = buf; sprintf(buf, "Content-Length: %ld\r\n", size); http_cmd[4] = "Connection: close\r\n"; http_cmd[5] = "Server: MYWEBSer\r\n"; http_cmd[6] = "Content-Language: zh-CN\r\n\r\n"; for (int 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) { if (send_head(conn, filename, type) != 0) { dprintf(conn, "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"); return 1; } int fd = open(filename, O_RDONLY); if (-1 == fd) { perror("open file to send"); return 1; } char buf[4096] = {0}; int rd_ret; while ((rd_ret = read(fd, buf, sizeof(buf))) > 0) { send(conn, buf, rd_ret, 0); } close(fd); return 0; }

三、服务器主流程

int main(int argc, char** argv) { int listfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == listfd) { perror("socket"); return 1; } // 端口复用 int opt = 1; setsockopt(listfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in ser, cli; bzero(&ser, sizeof(ser)); ser.sin_family = AF_INET; ser.sin_port = htons(80); ser.sin_addr.s_addr = INADDR_ANY; if (bind(listfd, (SA)&ser, sizeof(ser)) == -1) { perror("bind"); return 1; } if (listen(listfd, 128) == -1) { perror("listen"); return 1; } printf("Server is running on port 80...\n"); socklen_t len = sizeof(cli); while (1) { int conn = accept(listfd, (SA)&cli, &len); if (-1 == conn) { if (errno == EINTR) continue; perror("accept"); continue; } char buf[1024] = {0}; int ret = recv(conn, buf, sizeof(buf) - 1, 0); if (ret <= 0) { close(conn); continue; } char method[16], url[512], ver[16]; sscanf(buf, "%s %s %s", method, url, ver); // 路由分发 if (strcmp(method, "GET") != 0) { dprintf(conn, "HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n"); } else if (strcmp(url, "/") == 0) { send_file(conn, "./03.html", FILE_HTML); } else if (strncmp(url, "/register?", 10) == 0) { // 注册逻辑 } else if (strncmp(url, "/login?", 7) == 0) { // 登录逻辑 } else if (strncmp(url, "/search?", 8) == 0) { // 搜索逻辑 } else if (strncmp(url, "/detail_", 8) == 0) { // 详情逻辑 } else if (strstr(url, ".html")) { send_file(conn, url + 1, FILE_HTML); } else { dprintf(conn, "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"); } close(conn); } close(listfd); return 0; }

四、编译与运行

1. 编译命令

需链接 SQLite3 库,编译命令如下:

gcc 04ser.c -o web_shop -lsqlite3 -Wall

2. 运行前准备

创建 SQLite3 数据库文件 123.db,并初始化表结构:

-- 用户表 CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, pass TEXT NOT NULL ); -- 商品表 CREATE TABLE goods ( goods_id INTEGER PRIMARY KEY, goods_name TEXT NOT NULL, goods_img TEXT, goods_desc TEXT );

准备前端 HTML 文件(03.html/04.html/06.html/07.html)及商品图片资源。

3. 启动服务器

./web_shop

浏览器访问 http://127.0.0.1 即可进入商城首页。

五、核心优化点

  1. 防 SQL 注入:全程使用 SQLite3 预处理语句(sqlite3_prepare_v2 + 绑定参数),避免拼接 SQL 字符串。
  2. URL 解码:处理前端传递的编码参数,保证中文 / 特殊字符正常显示。
  3. 资源类型适配:支持 HTML、PNG、JPG、ICO 等多种文件类型的 HTTP 响应。
  4. 错误处理:完善的文件操作、数据库操作错误处理,提升稳定性。
  5. 端口复用:设置SO_REUSEADDR选项,避免服务器重启时端口占用问题。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 11:54:03

浏览器扩展开发:网页划词即时翻译功能实现路径

浏览器扩展开发&#xff1a;网页划词即时翻译功能实现路径 &#x1f4cc; 引言&#xff1a;让翻译更“顺手”的用户体验需求 在日常浏览英文网页时&#xff0c;用户常面临“看得懂但费劲”或“完全看不懂”的困境。虽然已有大量在线翻译工具&#xff08;如谷歌翻译、DeepL&am…

作者头像 李华
网站建设 2026/5/25 0:53:29

8.2 磁悬浮刚性转子动力学:基于磁轴承支承的转子系统建模与稳定性分析

8.2 磁悬浮刚性转子动力学:基于磁轴承支承的转子系统建模与稳定性分析 磁悬浮轴承的最终目标是实现转子在五个受控自由度上的稳定、高性能悬浮与旋转。第5.1节所述的单自由度模型揭示了系统稳定性的基本原理,但实际转子是一个具有质量分布和转动惯量的连续体,其动力学行为远…

作者头像 李华
网站建设 2026/5/30 1:59:26

CSANMT模型在电商产品评论翻译的情感保留

CSANMT模型在电商产品评论翻译的情感保留 &#x1f310; AI 智能中英翻译服务 (WebUI API) 项目背景与业务需求 随着跨境电商的迅猛发展&#xff0c;海量中文产品评论需要被快速、准确地翻译成英文&#xff0c;供海外用户参考。然而&#xff0c;传统机器翻译系统在处理用户生成…

作者头像 李华
网站建设 2026/5/20 14:57:06

如何用CSANMT构建支持历史记录的翻译应用?

如何用CSANMT构建支持历史记录的翻译应用&#xff1f; &#x1f310; AI 智能中英翻译服务 (WebUI API) 在多语言交流日益频繁的今天&#xff0c;高质量、低延迟的自动翻译系统已成为开发者和企业不可或缺的工具。传统的翻译服务往往依赖云端API&#xff0c;存在隐私泄露、网络…

作者头像 李华
网站建设 2026/5/23 19:09:59

10. Linux 系统启动原理

CentOS 7 启动过程 现代计算机系统是硬件与软件的复杂组合。从加电状态开始&#xff0c;到拥有登录提示符的运行中系统&#xff0c; 这需要大量的硬件和软件配合工作。 以下列表从较高层面概述了 CentOS7 启动过程。 计算机接通电源。系统固件&#xff08;现代UEFI或更旧的BIO…

作者头像 李华
网站建设 2026/5/21 11:34:06

翻译服务客户端SDK:简化CSANMT集成的开发工具

翻译服务客户端SDK&#xff1a;简化CSANMT集成的开发工具 &#x1f310; AI 智能中英翻译服务 (WebUI API) 在跨语言交流日益频繁的今天&#xff0c;高质量、低延迟的自动翻译能力已成为众多应用的核心需求。无论是国际化产品的内容本地化&#xff0c;还是开发者构建多语言支持…

作者头像 李华