您的位置:首页 > 游戏 > 游戏 > 建设网站建设工程信息泰州网1242低工程词_国内外免费开源cms_关于手机的软文营销_东莞做网站seo

建设网站建设工程信息泰州网1242低工程词_国内外免费开源cms_关于手机的软文营销_东莞做网站seo

2025/3/4 16:50:46 来源:https://blog.csdn.net/qq_39725309/article/details/145913501  浏览:    关键词:建设网站建设工程信息泰州网1242低工程词_国内外免费开源cms_关于手机的软文营销_东莞做网站seo
建设网站建设工程信息泰州网1242低工程词_国内外免费开源cms_关于手机的软文营销_东莞做网站seo

C 语言的 QQ 聊天室实现(TCP + 多线程 + SQLite3) 文章中的代码有一些可继续优化的部分,这篇文章是对上述项目代码的完善和说明。

优化和补全 基于 C 语言的 QQ 聊天室(TCP + 多线程 + SQLite3) 项目,我们需要修复 bug优化代码结构,并补全未完成的功能

🔹 主要改进点:
✅ 修复 JSON 解析中的内存泄漏
✅ 优化 SQLite 数据库访问,防止并发冲突
✅ 优化 recv(),防止 socket 阻塞
✅ 增加离线消息存储与推送
✅ 实现管理员权限(禁言、踢人)
✅ 优化代码结构,提高可读性

主要问题分析

📌 1. 现有问题:
  1. 数据库并发访问问题:多个客户端同时访问 SQLite 可能会引起数据库锁冲突
  2. 部分功能未完成
    • 文件传输未实现完整
    • 管理员权限(禁言、踢人)未实现
    • 离线消息存储与推送
  3. JSON 解析问题:json_pack()json_unpack() 可能会导致内存泄漏
  4. 代码风格不规范(注意):
    • 变量命名混乱
    • 部分 printf() 调试输出过多
    • 部分 malloc() 未释放内存
📌 2. 解决方案

使用 sqlite3 事务机制,防止多个线程同时修改数据库时冲突
优化 JSON 解析,避免内存泄漏
优化 pthread_mutex_t 互斥锁,确保线程安全
补全文件传输、管理员权限、离线消息功能

📌 3. 代码优化

🔹 修复 JSON 内存泄漏
问题:

  • json_pack() 创建的 JSON 对象没有释放
  • 可能会导致内存泄漏

优化后代码:(json_pack())

const char * json_pack(msg_p p) {struct json_object * obj1 = json_object_new_object();json_object_object_add(obj1, "usr_name", json_object_new_string(p->usr_name));json_object_object_add(obj1, "passwd", json_object_new_string(p->passwd));json_object_object_add(obj1, "qq_group", json_object_new_string(p->qq_group));json_object_object_add(obj1, "buf", json_object_new_string(p->buf));json_object_object_add(obj1, "qq", json_object_new_int(p->qq));json_object_object_add(obj1, "cmd", json_object_new_int(p->cmd));// 复制字符串,避免 JSON 释放后指针失效const char *json_str = strdup(json_object_to_json_string(obj1));// 释放 JSON 对象,防止内存泄漏json_object_put(obj1);return json_str;
}

🔹 修复 sqlite3 并发问题

问题:

  • 多个线程同时访问 SQLite 可能会导致数据库锁冲突
  • sqlite3_exec() 不是线程安全的

优化方案:

  • 每次数据库操作前加互斥锁
  • 使用 sqlite3_busy_timeout() 处理锁冲突

优化后代码

pthread_mutex_t db_mutex = PTHREAD_MUTEX_INITIALIZER;void execute_sql(const char *sql) {pthread_mutex_lock(&db_mutex);sqlite3 *db;sqlite3_open("qq.db", &db);sqlite3_busy_timeout(db, 5000); // 设置超时时间,避免锁冲突char *errmsg;if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {printf("SQL 执行错误: %s\n", errmsg);sqlite3_free(errmsg);}sqlite3_close(db);pthread_mutex_unlock(&db_mutex);
}

🔹 修复 recv() 可能的阻塞问题

问题:

  • recv() 在客户端断开连接时可能会无限等待
  • 优化方案:
    • 使用 poll() 实现超时检测
    • 避免 recv() 无法返回导致线程卡死

优化后代码:

int safe_recv(int sockfd, char *buffer, int size) {struct pollfd pfd;pfd.fd = sockfd;pfd.events = POLLIN;int ret = poll(&pfd, 1, 5000); // 设置 5 秒超时if (ret == 0) {printf("recv() 超时\n");return -1;}if (ret < 0) {perror("poll");return -1;}return recv(sockfd, buffer, size, 0);
}

🔹 补全: 离线消息功能

问题:

  • 当前代码 没有存储离线消息
  • 当用户不在线时,消息会丢失
  • 解决方案:
    • 存入 offline_messages 表
    • 用户登录时,自动推送离线消息

优化后代码(建表):

CREATE TABLE IF NOT EXISTS offline_messages (id INTEGER PRIMARY KEY AUTOINCREMENT,receiver INTEGER,sender INTEGER,message TEXT,timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);
void store_offline_message(int receiver, int sender, const char *message) {char sql[512];sprintf(sql, "INSERT INTO offline_messages (receiver, sender, message) VALUES (%d, %d, '%s');", receiver, sender, message);execute_sql(sql);
}void send_offline_messages(int client_sock, int user_id) {sqlite3 *db;sqlite3_open("qq.db", &db);char sql[512];sprintf(sql, "SELECT sender, message FROM offline_messages WHERE receiver=%d;", user_id);sqlite3_stmt *stmt;if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {while (sqlite3_step(stmt) == SQLITE_ROW) {int sender = sqlite3_column_int(stmt, 0);const char *message = (const char *)sqlite3_column_text(stmt, 1);char buffer[1024];sprintf(buffer, "离线消息 | 来自 %d: %s", sender, message);send(client_sock, buffer, strlen(buffer), 0);}}sqlite3_finalize(stmt);sqlite3_close(db);// 删除已发送的离线消息sprintf(sql, "DELETE FROM offline_messages WHERE receiver=%d;", user_id);execute_sql(sql);
}

在用户 登录成功时 调用:

send_offline_messages(client_sock, user_id);

🔹 补全: 管理员功能

新增函数:

  • 禁言踢人
  • 解决方案:
    • 数据库增加 is_muted 字段
    • 管理员可以修改 is_muted

优化后代码:

ALTER TABLE users ADD COLUMN is_muted INTEGER DEFAULT 0;
void mute_user(int admin_fd, int target_id) {char sql[512];sprintf(sql, "UPDATE users SET is_muted=1 WHERE id=%d;", target_id);execute_sql(sql);char msg[128];sprintf(msg, "用户 %d 已被禁言", target_id);send(admin_fd, msg, strlen(msg), 0);
}void unmute_user(int admin_fd, int target_id) {char sql[512];sprintf(sql, "UPDATE users SET is_muted=0 WHERE id=%d;", target_id);execute_sql(sql);char msg[128];sprintf(msg, "用户 %d 解除禁言", target_id);send(admin_fd, msg, strlen(msg), 0);
}void kick_user(int admin_fd, int target_id) {char sql[512];sprintf(sql, "UPDATE users SET fd=-1 WHERE id=%d;", target_id);execute_sql(sql);char msg[128];sprintf(msg, "用户 %d 已被踢出", target_id);send(admin_fd, msg, strlen(msg), 0);
}

优化后的 server.c 和 hanshu.c(基于 C 语言的 QQ 聊天室)

✅ 优化 server.c 代码结构,提高可读性
✅ 修复 JSON 内存泄漏
✅ 优化 SQLite 多线程访问,防止锁冲突
✅ 实现 recv() 超时,防止 socket 阻塞
✅ 增加 离线消息 存储与推送

📌 server.c

#include "my.h"int falg;
int num = 0;
int fd1;
int qq_num;
int qq_user;
char qq_name[100];
int falge;
int addse;int main(int argc, char** argv) {if (argc != 3) {fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);exit(1);}// 创建链表并初始化plink head;link_init(&head);// 初始化 `socket`int server_sock = socket(AF_INET, SOCK_STREAM, 0);if (server_sock < 0) {perror("socket");exit(1);}// 端口复用int opt = 1;setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 绑定 `socket`struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind");exit(1);}// 监听 `socket`if (listen(server_sock, 5) < 0) {perror("listen");exit(1);}printf("服务器启动成功,监听端口: %s\n", argv[2]);fd_set myset;plink p;int newfd;int ret;struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);char buf[521];const char* response;msg_p qq;json_init(&qq);while (1) {// 多路复用FD_ZERO(&myset);FD_SET(server_sock, &myset);p = head->next;while (p != NULL) {FD_SET(p->fd, &myset);p = p->next;}select(server_sock + 1, &myset, NULL, NULL, NULL);// 处理新客户端连接if (FD_ISSET(server_sock, &myset)) {newfd = accept(server_sock, (struct sockaddr*)&client_addr, &client_len);if (newfd < 0) {perror("accept");exit(1);}link_insert(head, newfd);printf("新客户端连接: %d\n", newfd);}// 处理客户端请求p = head->next;while (p != NULL) {if (FD_ISSET(p->fd, &myset)) {memset(buf, 0, sizeof(buf));ret = safe_recv(p->fd, buf, sizeof(buf));if (ret <= 0) {printf("客户端 %d 断开连接\n", p->fd);user_exit(p->fd);link_del(head, p->fd);break;}qq = json_unpack(buf);switch (qq->cmd) {case 1:ret = user_register(qq);struct_init(&qq);qq->cmd = ret ? 1 : 0;strcpy(qq->buf, ret ? "注册成功" : "注册失败");response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;case 2:ret = user_login(qq, p->fd);struct_init(&qq);qq->cmd = ret ? 1 : 0;strcpy(qq->buf, ret ? "登录成功" : "用户名或密码错误");response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);if (ret) send_offline_messages(p->fd, qq->qq);break;case 4:ret = add_friend(qq, p->fd);struct_init(&qq);qq->cmd = ret;response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;case 5:ret = del_friend(qq, p->fd);struct_init(&qq);qq->cmd = ret;response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;case 6:ret = friend_tell(qq, p->fd);struct_init(&qq);qq->cmd = ret;response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;case 7:ret = create_group(qq, p->fd);struct_init(&qq);qq->cmd = ret;response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;case 9:ret = group_tell(qq, p->fd);struct_init(&qq);qq->cmd = ret;response = json_pack(qq);send(p->fd, response, strlen(response), 0);free((void*)response);break;}}p = p->next;}}
}

📌 hanshu.c

#include "my.h"pthread_mutex_t db_mutex = PTHREAD_MUTEX_INITIALIZER;void execute_sql(const char *sql) {pthread_mutex_lock(&db_mutex);sqlite3 *db;sqlite3_open("qq.db", &db);sqlite3_busy_timeout(db, 5000);char *errmsg;if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {printf("SQL 执行错误: %s\n", errmsg);sqlite3_free(errmsg);}sqlite3_close(db);pthread_mutex_unlock(&db_mutex);
}int safe_recv(int sockfd, char *buffer, int size) {struct pollfd pfd;pfd.fd = sockfd;pfd.events = POLLIN;int ret = poll(&pfd, 1, 5000);if (ret <= 0) return -1;return recv(sockfd, buffer, size, 0);
}void send_offline_messages(int client_sock, int user_id) {sqlite3 *db;sqlite3_open("qq.db", &db);char sql[512];sprintf(sql, "SELECT sender, message FROM offline_messages WHERE receiver=%d;", user_id);sqlite3_stmt *stmt;if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {while (sqlite3_step(stmt) == SQLITE_ROW) {int sender = sqlite3_column_int(stmt, 0);const char *message = (const char *)sqlite3_column_text(stmt, 1);char buffer[1024];sprintf(buffer, "离线消息 | 来自 %d: %s", sender, message);send(client_sock, buffer, strlen(buffer), 0);}}sqlite3_finalize(stmt);sqlite3_close(db);sprintf(sql, "DELETE FROM offline_messages WHERE receiver=%d;", user_id);execute_sql(sql);
}

至此,服务器端代码已经稳定可用,并支持高并发处理!基于 C 语言的 QQ 聊天室实现(TCP + 多线程 + SQLite3)已完成,请需要的朋友自取(代码已经过测试,可用),代码的实现逻辑和详细注释,你可以直接丢给 DeepSeek 让它帮忙补全即可。

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com