YYDD125 2024-06-09 14:21 采纳率: 11.1%
浏览 16
已结题

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

当收到消息时,几次收到同一个消息,有时就会崩溃,当首位是空格也会崩溃,和字数无关,短的和长的都有可能发生
如下日志

~/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 <je_large_dalloc+32>
cpsr           0x60010030          1610678320
fpscr          0x80000000          -2147483648
tpidruro       <unavailable>
(gdb) frame
#0  0xf777c5c0 in je_large_dalloc ()
   from /apex/com.android.runtime/lib/bionic/libc.so

如下代码


#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

  • 写回答

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语言标准库中没有,但可以通过其他库实现)。
    • 确保代码风格一致,增加注释,以提高代码的可读性和可维护性。

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

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月22日
  • 创建了问题 6月9日

悬赏问题

  • ¥15 IEd中开关量采样信号通道设计
  • ¥45 字符串操作——数组越界问题
  • ¥15 Loss下降到0.08时不在下降调整学习率也没用
  • ¥15 QT+FFmpeg使用GPU加速解码
  • ¥15 为什么投影机用酷喵播放电影放一段时间就播放不下去了?提示发生未知故障,有什么解决办法吗?
  • ¥15 来个会搭建付费网站的有偿
  • ¥100 有能够实现人机模式的c/c++代码,有图片背景等,能够直接进行游戏
  • ¥20 校园网认证openwrt插件
  • ¥15 以AT89C51单片机芯片为核心来制作一个简易计算器,外部由4*4矩阵键盘和一个LCD1602字符型液晶显示屏构成,内部由一块AT89C51单片机构成,通过软件编程可实现简单加减乘除。
  • ¥15 求GCMS辅导数据分析