• 总是莫名其妙的发生段错误


    关注 码龄 粉丝数 原力等级 -- 被采纳 被点赞 采纳率 YYDD125 2024-06-09 14:21 采纳率: 14.3% 浏览 4 首页/ 编程语言 / 总是莫名其妙的发生段错误 c语言缓存websocket 当收到消息时,几次收到同一个消息,有时就会崩溃,当首位是空格也会崩溃,和字数无关,短的和长的都有可能发生如下日志 ~/libws $ ./lw [2024/06/09 14:17:34:1563] N: lws_create_context: LWS: 4.3.3-no_hash, NET CLI SRV H1 H2 WS ConMon IPv6-absent [2024/06/09 14:17:34:1574] N: __lws_lc_tag: ++ [wsi|0|pipe] (1) [2024/06/09 14:17:34:1575] N: __lws_lc_tag: ++ [vh|0|default||7681] (1) [2024/06/09 14:17:34:1577] N: [vh|0|default||7681]: lws_socket_bind: source ads 0.0.0.0 [2024/06/09 14:17:34:1577] N: __lws_lc_tag: ++ [wsi|1|listen|default||7681] (2) Starting server... [2024/06/09 14:17:37:5358] N: __lws_lc_tag: ++ [wsisrv|0|adopted] (1) Connection established Received msg: login admin 5431 Login successful for user: admin User admin logged in 无法打开留言板文件: No such file or directory //此处正常,因为没有留言程序能够正常处理 0xf0532700Received msg: sent admin ssjii sjaja sjsk .njj Received msg: sent admin jdiajb shshsba sbajs Received msg: sent admin ssjii sjaja sjsk .njj Received msg: sent admin ssjii sjaja sjsk .njj Segmentation fault Program received signal SIGSEGV, Segmentation fault. 0xf777c5c0 in je_large_dalloc () from /apex/com.android.runtime/lib/bionic/libc.so (gdb) bt #0 0xf777c5c0 in je_large_dalloc () from /apex/com.android.runtime/lib/bionic/libc.so #1 0xf77620a4 in je_free () from /apex/com.android.runtime/lib/bionic/libc.so #2 0x004034cc in callback (wsi=0xf791c700, reason=LWS_CALLBACK_RECEIVE, user=0x0, in=0xf7cbf4e0, len=1910) at main.c:597 #3 0xf789d7c2 in ?? () from /data/data/com.termux/files/usr/lib/libwebsockets.so Backtrace stopped: previous frame identical to this frame (corrupt stack?) (gdb) info registers r0 0x686c6 427718 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0xf7b7a008 4156006408 r5 0xf 15 r6 0x0 0 r7 0x0 0 r8 0xf77e925c 4152267356 r9 0xf7c00000 4156555264 r10 0xf7b7a0a4 4156006564 r11 0xf7cbf4e0 4157338848 r12 0xf77e4ec8 4152250056 sp 0xfffee8d0 0xfffee8d0 lr 0xf77620a5 -143253339 pc 0xf777c5c0 0xf777c5c0 cpsr 0x60010030 1610678320 fpscr 0x80000000 -2147483648 tpidruro (gdb) frame #0 0xf777c5c0 in je_large_dalloc () from /apex/com.android.runtime/lib/bionic/libc.so 如下代码 #include #include #include #include #define MAX_USERNAME_LENGTH 256 #define MAX_PASSWORD_LENGTH 256 #define MAX_CLIENTS 64 #define MAX_LEN 8192 #define de puts("part");getchar(); typedef struct client_info { struct lws *wsi; // WebSocket连接指针 char username[MAX_USERNAME_LENGTH]; // 用户名 } client_info_t; // 客户端数组 client_info_t clients[MAX_USERNAME_LENGTH] = { 0 }; int num_clients = 0; int send_to_client_by_username (const char *comeusername, const char *username,const char *message, int length); int is_wsi_in_clients (struct lws *wsi) { for (int i = 0; i < num_clients; i++) { if (clients[i].wsi == wsi) { // 找到了匹配的wsi,它存在于数组中 return 1; } } // 没有找到匹配的wsi,它不存在于数组中 return 0; } //FILE IO FUC********************************** int count_characters(const char *filename, FILE *file) { int count = 0; if(file==NULL){ if(filename){ file = fopen(filename, "r"); } } if (file == NULL) { perror("Error opening file"); return -1; } int ch; while ((ch = fgetc(file)) != EOF) { count++; } fclose(file); return count; } int count_lines_with_string (const char *filename, const char *str) { char *line = NULL; // 动态分配每行内容 size_t linecap = 0; // 保存当前分配的容量 int count = 0; FILE *file = fopen (filename, "r"); if (file == NULL) { perror ("打开文件时出错"); return -1; } while (getline (&line, &linecap, file) != -1) { // 删除行尾的换行符 size_t len = strlen (line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } if (strstr (line, str) != NULL) { count++; } } if (ferror (file)) { perror ("读取文件时出错"); fclose (file); free (line); // 释放分配的内存 return -1; } fclose (file); free (line); // 释放分配的内存 return count; } /***/ void append_message_if_user_exists(const char *username, const char *msg) { // 检查usr.ini中是否存在username //if (count_lines_with_string("usr.ini", username) > 0) { // 构造leave.ini文件名 char leave_file[256]; snprintf(leave_file, sizeof(leave_file), "%sleave.ini", username); // 以追加模式打开文件 FILE *file = fopen(leave_file, "a"); if (file == NULL) { perror("无法打开文件"); return; } // 追加msg并换行 fprintf(file, "%s\n", msg); fclose(file); //} } // 函数:删除文件的指定行 int delete_line (const char *filename, int line_to_delete) { // 创建临时文件名 char temp_filename[300]; strcpy (temp_filename, filename); strcat (temp_filename, ".tmp"); // 打开源文件和临时文件 FILE *source = fopen (filename, "r"); FILE *temp = fopen (temp_filename, "w"); if (source == NULL || temp == NULL) { perror ("Error opening file(s)"); return -1; } // 行计数器 int line_counter = 0; char buffer[1024]; // 读取并处理每一行 while (fgets (buffer, sizeof (buffer), source)) { // 如果当前行不是要删除的行,则写入临时文件 if (line_counter != line_to_delete) { fputs (buffer, temp); } line_counter++; } // 关闭文件 fclose (source); fclose (temp); // 删除原始文件 remove (filename); // 将临时文件重命名为原始文件名 if (rename (temp_filename, filename) != 0) { perror ("Error renaming file"); return -1; } puts ("更新成功"); return 0; } //FILE IO FUC OVER--------------- //InteractIve IO FUC************************************ void handle_message_board(const char *username) { // 构造留言板文件名 char message_board_file[300]; snprintf(message_board_file, sizeof(message_board_file), "%sleave.ini", username); char message_history_file[300]; snprintf(message_history_file, sizeof(message_history_file), "%shistory.ini", username); // 打开留言板文件 FILE *history = fopen(message_history_file, "a"); if (history == NULL) { perror("无法打开历史文件"); return; } FILE *file = fopen(message_board_file, "r"); if (file == NULL) { fclose(history); perror("无法打开留言板文件"); return; } // 发送"留言记录"消息 const char *start_msg = "留言记录"; send_to_client_by_username (NULL, username, start_msg, strlen(start_msg)); fprintf(history,"%s\n",start_msg); fflush(history); // 读取并发送留言板内容 char *line = NULL; size_t len = 0; ssize_t read; while ((read = getline(&line, &len, file)) != -1) { // 去除换行符 line[strcspn(line, "\n")] = 0; // 发送当前行 send_to_client_by_username (NULL, username, line, strlen(line)); fprintf(history,"%s\n",line); fflush(history); } // 发送"留言完毕"消息 const char *end_msg = "留言完毕"; send_to_client_by_username (NULL, username, end_msg, strlen(end_msg)); fprintf(history,"%s\n",end_msg); fflush(history); // 清理资源 fclose(file); fclose(history); if (line) { free(line); } // 删除留言板文件 if (remove(message_board_file) != 0) { perror("无法删除留言板文件"); } } // 发送函数 int send_to_client_by_username (const char *comeusername, const char *username,const char *message, int length) { char *combined; // 分配足够的空间来存放合并后的字符串 size_t combined_length = strlen (username) + strlen (message) + 2; // 加2是为了包括':'和'\0' combined = (char *) malloc (combined_length * sizeof (char)); if (combined == NULL) { // 分配内存失败 fprintf (stderr, "Memory allocation failed\n"); return 1; } // 使用sprintf来格式化字符串 if(comeusername){ sprintf (combined, "%s:%s", comeusername, message); }else{ sprintf (combined, "%s", message); } for (int i = 0; i < num_clients; i++) { if (strcmp (clients[i].username, username) == 0) { // 找到匹配的用户名,发送消息 lws_write (clients[i].wsi, (unsigned char *) combined, strlen (combined), LWS_WRITE_TEXT); free (combined); return 0; } } // 没有找到匹配的用户名 free (combined); return -1; } /***/ int sentToFriend (const char *username, const char *toUsername, const char *message, int length) { char filename[300]; snprintf (filename, sizeof (filename), "%sfriend.ini", toUsername); if (count_lines_with_string (filename, username) > 0) { if (send_to_client_by_username (username, toUsername, message, length) == 0) { return 0; } else if (count_lines_with_string ("usr.ini", toUsername) > 0) { return 1; } } else { return -1; } return -1; } /***/ int handle_login (struct lws *wsi, const char *username) { if (num_clients >= MAX_CLIENTS) { lwsl_err ("Too many clients connected\n"); return -1; } // 查找空闲位置存储客户端信息 for (int i = 0; i < MAX_CLIENTS; i++) { if (clients[i].wsi == NULL) { clients[i].wsi = wsi; strncpy (clients[i].username, username, MAX_USERNAME_LENGTH - 1); clients[i].username[MAX_USERNAME_LENGTH - 1] = '\0'; // 确保字符串以null结尾 num_clients++; printf ("User %s logged in\n", username); return 0; // 登录成功 } } lwsl_err ("No free slot for new client\n"); return -1; // 登录失败 } char message[] = "用户错误"; //OVER------------------------------ //函数回调************************************** static int callback (struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { switch (reason) { //建立回调................... case LWS_CALLBACK_ESTABLISHED: printf ("Connection established\n"); break; //接收消息..................... case LWS_CALLBACK_RECEIVE: // printf("Received data: %s\n", (char *)in); (char *) in; char *msg = (char *) in; for (int i = 0; i < strlen(msg); i++) { if (msg[i] == '\n' || msg[i] == '\r') { msg[i] = ' '; } } msg[len] = '\0'; // 确保字符串以null终止 printf ("Received msg: %s\n", msg); /* 登录处理 */ if (strncasecmp (msg, "login", 5) == 0 && is_wsi_in_clients (wsi) == 0) { char *token; char *username = NULL; char *password = NULL; // 获取第一个 token("login") token = strtok (msg, " "); if (token == NULL) return 1; // 跳过 "login",获取 "username" token = strtok (NULL, " "); // 动态分配内存并复制 "username" if (token == NULL) return 1; username = (char *) malloc (strlen (token) + 1); if (username != NULL&&token) { strcpy (username, token); } // 获取 "password" token = strtok (NULL, " "); if(token==NULL){ return 1; } // 动态分配内存并复制 "password" password = (char *) malloc (strlen (token) + 1); if (password != NULL) { strcpy (password, token); } FILE *file = fopen ("usr.ini", "r"); if (!file) { perror ("Error opening file"); return 1; } char line[512]; // 假设每行最大长度为511个字符 char usernameINI[256]; char passwordINI[256]; int found = 0; // 逐行读取文件 while (fgets (line, sizeof (line), file)) { // 去除换行符 line[strcspn (line, "\n")] = 0; // 使用fscanf读取用户名和密码 if (sscanf (line, "%s %s", usernameINI, passwordINI) == 2) { // 比较用户名 if (strcmp (usernameINI, username) == 0) { found = 1; // 比较密码 if (strcmp (passwordINI, password) == 0) { printf ("Login successful for user: %s\n", usernameINI); if (handle_login (wsi, username) != -1) { char err[] = "登录成功"; lws_write (wsi, (unsigned char *) err, strlen (err), LWS_WRITE_TEXT); printf("%p",wsi); handle_message_board(username); } else { char err[] = "用户过多"; lws_write (wsi, (unsigned char *) err, strlen (err), LWS_WRITE_TEXT); lws_close_reason (wsi, LWS_CLOSE_STATUS_NORMAL, NULL, 0); lws_context_destroy (lws_get_context (wsi)); } } else { printf ("Incorrect password for user: %s\n", usernameINI); char err[] = "密码错误"; lws_write (wsi, (unsigned char *) err, strlen (err), LWS_WRITE_TEXT); } break; } } } if (!found) { printf ("User not found: %s\n", username); char err[] = "用户不存在"; lws_write (wsi, (unsigned char *) err, strlen (err), LWS_WRITE_TEXT); } // 关闭文件 fclose (file); free (username); free (password); } /* 发送给用户 */ else if (strncasecmp (msg, "sent", 4) == 0 && is_wsi_in_clients (wsi)) { char *firstSpace = strchr (msg, ' '); if (firstSpace == NULL) { printf ("没有空格找到\n"); return 1; } // 跳过第一个空格,指向username firstSpace++; // 现在firstSpace指向username的第一个字符 // 找到第二个空格的位置 char *secondSpace = strchr (firstSpace, ' '); if (secondSpace == NULL) { printf ("没有第二个空格找到\n"); return 1; } // 计算username的长度 int usernameLength = secondSpace - firstSpace; // 动态分配内存以存储username char *username = (char *) malloc (usernameLength + 1); // 加1是为了存储'\0' if (username == NULL) { printf ("内存分配失败\n"); return 1; } // 复制username strncpy (username, firstSpace, usernameLength); username[usernameLength] = '\0'; // 确保字符串以'\0'结尾 // 现在secondSpace指向textmsg的开始,跳过空格 secondSpace++; // 计算textmsg的长度 int textmsgLength = strlen (secondSpace); // 动态分配内存以存储textmsg char *textmsg = (char *) malloc (textmsgLength + 1); // 加1是为了存储'\0' if (textmsg == NULL) { printf ("内存分配失败\n"); free (username); // 在退出前释放已分配的内存 free (secondSpace); free (firstSpace); return 1; } // 复制textmsg strncpy (textmsg, secondSpace, textmsgLength); textmsg[textmsgLength] = '\0'; // 确保字符串以'\0'结尾 for (int i = 0; i < num_clients; i++) if (clients[i].wsi == wsi) { int iee = sentToFriend (clients[i].username, username, textmsg, strlen (textmsg)); if (iee == -1) { char err[] = "用户不存在或不是你的好友"; lws_write (wsi, (unsigned char *) err, strlen (err), LWS_WRITE_TEXT); } else if (iee == 1) { char errs[] = "用户未登录,已尝试留言"; lws_write (wsi, (unsigned char *) errs, strlen (errs), LWS_WRITE_TEXT); append_message_if_user_exists(username, textmsg); } } free (username); free (secondSpace); free (firstSpace); } /* 指令:好友处理 */ else if (strncasecmp (msg, "friend", 6) == 0 && is_wsi_in_clients (wsi)) { for (int i = 0; i < num_clients; i++) { if (clients[i].wsi == wsi) { char *username = clients[i].username; char *filename; size_t username_len = strlen (username); size_t filename_len = username_len + strlen ("friend.ini") + 1; // 加1是为了'\0'终止符 // 动态分配内存 filename = (char *) malloc (filename_len * sizeof (char)); if (filename == NULL) { perror ("Memory allocation failed"); return 1; } // 拼接文件名 snprintf (filename, filename_len, "%sfriend.ini", username); // 处理命令 if (strstr (msg, "friend add")) { FILE *file = fopen (filename, "a"); // "r+" 模式表示读写模式 if (file == NULL) { perror ("Error opening file"); free (filename); // 释放内存 return 1; } // 将新的朋友名添加到文件中 char *friend_name = msg + strlen ("friend new "); fprintf (file, "%s\n", friend_name); fclose (file); } else if (strstr (msg, "friend rm")) { char *friend_name = msg + strlen ("friend rm "); int lin = count_lines_with_string (filename, friend_name) - 1; delete_line (filename, lin); } // 关闭文件 // 释放内存 free (filename); } } } free (msg); //lws_callback_on_writable(wsi); break; case LWS_CALLBACK_SERVER_WRITEABLE: lws_write (wsi, (unsigned char *) message, strlen (message), LWS_WRITE_TEXT); break; case LWS_CALLBACK_CLOSED: printf ("Connection closed\n"); // 客户端断开连接时,清理客户端信息 for (int i = 0; i < num_clients; i++) { if (clients[i].wsi == wsi) { memset (&clients[i], 0, sizeof (client_info_t)); num_clients--; break; } } break; default: break; } return 0; } static struct lws_protocols protocols[] = { { "ocp-protocol", callback, 0, 0, }, {NULL, NULL, 0, 0} /* End of list */ }; //MAIN FUC int main () { struct lws_context_creation_info info; memset (&info, 0, sizeof (info)); info.port = 7681; info.iface = NULL; info.protocols = protocols; info.ssl_cert_filepath = "./certificate.pem"; info.ssl_private_key_filepath = "./private.key"; info.gid = -1; info.uid = -1; info.options = 0; struct lws_context *context = lws_create_context (&info); if (context == NULL) { printf ("Failed to create context\n"); return 1; } printf ("Starting server...\n"); while (1) { lws_service (context, 50); } lws_context_destroy (context); return 0; } 展开全部 收起 写回答 好问题 0 提建议 追加酬金 关注问题 微信扫一扫 点击复制链接 分享 邀请回答 编辑 收藏 删除 结题 收藏 举报 追加酬金 (90%的用户在追加酬金后获得了解决方案) 当前问题酬金 ¥ 0 (可追加 ¥500) ¥ 15¥ 20¥ 50¥ 100¥ 200 支付方式 扫码支付 二维码出错 点击刷新 支付金额 15 元 提供问题酬金的用户不参与问题酬金结算和分配 支付即为同意 《付费问题酬金结算规则》 结题 再想想 删除 再等等

    1条回答 默认 最新

    • 阿里嘎多学长 2024-06-09 14:35
      关注

      以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


      根据您提供的信息和代码,我们可以从几个方面来分析和解决问题:

      1. 内存分配和访问问题

      崩溃发生在je_large_dalloc函数中,这通常与内存分配和释放有关。在C语言中,常见的内存问题包括:

      • 访问未初始化的内存
      • 访问已经释放的内存
      • 内存越界(数组越界等)

      2. 代码审查

      审查您的代码,特别是以下几个部分:

      • 内存分配:检查所有使用malloc的地方,确保每次分配后都有相应的free
      • 字符串操作:检查所有字符串操作,特别是使用strtok的地方,因为它会修改原始字符串,可能导致未预期的行为。
      • 文件操作:确保文件操作后都关闭了文件描述符,并且在打开文件失败时有适当的错误处理。

      3. 特定问题处理

      • 重复消息:如果收到重复消息导致崩溃,可能是因为消息处理逻辑中的某个部分对消息内容有特定的假设(比如格式)。检查消息处理逻辑,确保它能够处理各种格式的消息。
      • 首位空格:如果首位空格导致崩溃,可能是因为字符串处理时没有正确处理空格。检查所有字符串操作,确保它们能够处理空格。

      4. 调试和测试

      • 使用valgrind等工具检查内存泄漏和内存越界问题。
      • 编写单元测试来测试各种边界条件,包括重复消息和首位空格的情况。

      5. 代码示例修正

      以下是一些可能的问题和建议的修正:

      问题1:client_info_t clients[MAX_USERNAME_LENGTH]数组大小可能不正确。

      // 这里应该使用MAX_CLIENTS而不是MAX_USERNAME_LENGTH
      client_info_t clients[MAX_CLIENTS] = { 0 };
      

      问题2:在send_to_client_by_username函数中,如果找不到用户,应该释放combined

      // 在循环结束后添加
      free(combined);
      

      问题3:在handle_message_board函数中,如果文件打开失败,应该返回而不是继续执行。

      if (file == NULL) {
          fclose(history);
          perror("无法打开留言板文件");
          return;
      }
      

      6. 参考资料

      7. 其他建议

      • 考虑使用更现代的内存管理方法,比如智能指针(虽然C语言标准库中没有,但可以通过其他库实现)。
      • 确保代码风格一致,增加注释,以提高代码的可读性和可维护性。

      希望这些建议能帮助您解决问题。如果您需要更具体的代码实现或有其他问题,请随时提问。

      展开全部

      评论 编辑记录
      编辑
      预览

      报告相同问题?

    • 相关阅读:
      【C#】字符串拼接相关
      webpack常见的loader和plugins,及它们各自作用机制
      elasticsearch bulk 批量操作
      预编译、函数变量提升
      不知道电脑批量旋转图片怎么操作?手把手教会你
      再次尝试放出被屏蔽的百度蜘蛛网段
      【微信小程序】开发入门篇(一)
      MyBatis获取参数值的两种方式,MyBatis获取参数值的情况(5种)
      详解链表oJ<反转链表,链表的中间节点及链表的回文>
      VScode远程连接Linux入门
    • 原文地址:https://ask.csdn.net/questions/8116136