我们正在尝试进行 GMS 服务器/客户端聊天。我们在这部分代码上使用 atoi 时遇到问题

unserialize_tcp(buffer,&type, &grpname, &member_name, &received_addr, &received_port);
printf("1%s %s %s\n", grpname, member_name, received_addr);
addr = atoi(received_addr);
client.sin_addr.s_addr = addr;
client.sin_port = received_port;
printf("2%s %s \n", grpname, member_name);

输出是这样的,你可以看到在我们使用 atoi 后成员名称失去了原来的值

Succesfully created RECEIVER WORKER and SOCKET WORKER 

Available options
     type 'exit' to close gms  
BEFORE
AFTER
BEFORE
New Client socket 4 stored at index 0
packet 0_omada_onoma_16777343_26385
1omada onoma 16777343
2omada @���x 
3omada @���x 
4omada @���x 
Group omada just got a new member @���x 
We didn't notify every member of the group  about the new member

这是 unserialize_tcp 函数

void unserialize_tcp(char* message, type_t *type, char** grpname, char** member_name, char** received_addr, int* received_port) {

    char msg[TCP_PACKET] = {'\0'};
    char *saveptr;
    char *ptr = message;
    char *delim = "_";
    int i;
    for (i = 0; ptr[i]; ptr[i] == '_' ? i++ : *ptr++);
    if (i != 4) {
        printf("Message corrupted\n");
        return;
    }
    strcpy(msg, message);
    *type = atoi(strtok_r(msg, delim, &saveptr));
    *grpname = strtok_r(NULL, delim, &saveptr);
    *member_name = strtok_r(NULL, delim, &saveptr);
    *received_addr = strtok_r(NULL, delim, &saveptr);
    *received_port = atoi(strtok_r(NULL, delim, &saveptr));
    

}

这是 atoi 问题起源的 receive_worker 线程


void *gms_receive_worker(void *args) {
  int i;
  char buffer[TCP_PACKET];
  char *grpname = (char*)calloc(16, sizeof(char));
  char* member_name = (char*)calloc(16, sizeof(char));
  type_t type ;
  char* received_addr = (char*)calloc(LENGTH_MSG, sizeof(char));
  char *msg;
  msg = (char*) malloc(sizeof(char)*TCP_PACKET);
  int received_port, addr;
  
  struct sockaddr_in client;
  while(!flag) {
    for (i=0; i< MAX_CLIENTS; i++) {
      memset(buffer, '\0',sizeof(buffer));
      if (recv(client_sockets[i], (char*)buffer, TCP_PACKET, MSG_WAITALL) < 0 ) {
            continue;
      }
      
      if(strlen(buffer) > 0) {
        printf("packet %s\n", buffer);
        unserialize_tcp(buffer,&type, &grpname, &member_name, &received_addr, &received_port);
        printf("1%s %s %s\n", grpname, member_name, received_addr);
        addr = atoi(received_addr);
        client.sin_addr.s_addr = addr;
        client.sin_port = received_port;
         printf("2%s %s \n", grpname, member_name);
        if (type == EXIT_TCP_SOCKET) {
          printf(BOLDRED"Client exited and the socket %d just closed\n"RESET, client_sockets[i]);
          client_sockets[i] = 0;
          continue;
        }
        else if (type == GROUP_JOIN) {
          printf("3%s %s \n", grpname, member_name);
          if (search_gms_list(list, grpname, member_name) != NULL) {
            msg = serialize_tcp(GROUP_REJECT_MEMBER, grpname, member_name, received_addr, received_port);
            if(send(client_sockets[i], (const char *)msg, TCP_PACKET, MSG_NOSIGNAL) < 0 ) {
                printf(BOLDRED"Failed inside group join\n"RESET);
                exit(1);
            }
            continue;
          }
           printf("4%s %s \n", grpname, member_name);
          printf(BOLDRED"Group %s just got a new member %s \n"RESET, grpname, member_name);
          
          add_gms_list(list, grpname, member_name, client, client_sockets[i]);
          msg = serialize_tcp(GROUP_SOMEONE_JOINED, grpname, member_name, received_addr, received_port);
            
          if (gms_sender_worker(grpname,member_name, msg) == 1) {
            printf(CYAN"We notified every member of the group %s about the new member\n"RESET, grpname);
            continue;
          }
          else{
            printf(CYAN"We didn't notify every member of the group %s about the new member\n"RESET, grpname);
            continue;
          }
            
        }
        else if (type == GROUP_LEAVE ) {
          if (search_gms_list(list, grpname, member_name) == NULL) {
            msg = serialize_tcp(LEAVE_FAILED, grpname, member_name, received_addr, received_port);
            if(send(client_sockets[i], (const char *)msg, TCP_PACKET, MSG_NOSIGNAL) < 0 ) {
                printf(BOLDRED"Failed inside group join\n"RESET);
                exit(1);
            }
            continue;
          }
          printf(BOLDRED"Group %s lost the member %s \n"RESET, grpname, member_name);

          delete_gms_list(list, grpname, member_name, client);
          msg = serialize_tcp(GROUP_SOMEONE_LEFT, grpname, member_name, received_addr, received_port);
            
          if (gms_sender_worker(grpname,member_name, msg) == 1) {
            printf(CYAN"We notified every member of the group %s about the member that left\n"RESET, grpname);
            continue;
          }
          else{
            printf(CYAN"We didn't notify every member of the group %s about the member that left\n"RESET, grpname);
            continue;
          }
        }
        else{
          printf(BOLDRED"You are not supposed to see this \n"RESET);
        }
      }
    }
  }
  free(grpname);
  free(member_name);
  free(received_addr);
  free(msg);
  

  pthread_exit(NULL);
}


当我们将 atoi 放在注释中时,member_name 保留其原始值。问题很奇怪,我们找不到解决方案。任何想法表示赞赏谢谢!

我们的期望:我们没想到 atoi 会破坏另一个字符串的值,我们期望看到相同的打印语句。但我们不

6

  • 2
    欢迎来到SO。请尝试创建一个最小的可重现示例{(请参阅),并且不要发布输出的链接,而是将输出粘贴到问题中。顺便提一句。我确信会出现问题,因为member_name没有指向有效的地址,但如果没有完整的示例,就不可能说


    – 


  • 这是输出可用选项类型“exit”关闭gms之前之后之前新客户端套接字4存储在索引0数据包0_omada_onoma_16777343_26385 1omada onoma 16777343 2omada @���x 3omada @���x 4omada @��x Group omada just有一个新成员@�x 我们没有通知该组的每个成员有关新成员的信息


    – 


  • 这意味着你在其他地方有UB(不在提供的代码中)


    – 


  • atoi(family) 不建议使用,因为它没有明确定义的错误处理。您应该将其替换为等效的strtol(str, 0, 10).不一定是这里的错误,但始终遵循最佳实践。此外,strtol如果转换失败,还可以提供更多错误结果。


    – 


  • 我刚刚更新了帖子,你们可以再看一下吗?我们尝试使用 strtol 但问题仍然出现,也许我们没有正确使用它欢呼!


    – 


2 个回答
2

您需要删除 unserialize tcp 中的 msg 字符串并使用 msg 所在的消息

这是您的问题(至少是其中一个),共十几行:

int main()
{
    char* foo = malloc(100);
    bar(&foo);
}

void bar(char** arg)
{
   char example[] = "this is an example";
   *arg = strtok(example, " ");
}

或者,手动内联后bar

int main()
{
    char* foo = malloc(100);
    {
       char example[] = "this is an example";
       *foo = strtok(example, " ");
    }
}

您分配一个缓冲区以便将数据复制到其中。不是为了立即覆盖指向所述缓冲区的唯一现有指针,永远丢失分配的内存,并在进程中创建一个悬空指针(有关更多说明,请参阅

你需要的其实是这个

int main()
{
    char* foo = malloc(100);
    bar(foo); // note no &
}

void bar(char* arg) // note one star
{
   char example[] = "this is an example";
   strcpy(arg, strtok(example, " ")); // note no `=`
}