c - 当客户端尝试重新建立连接时,g_io_channel_unix_new() 调用会导致 SIGSEGV

标签 c glib websocket

您好,我正在尝试使用 glib API 实现 WebSocket 服务器。服务器成功与客户端(Chrome 浏览器)握手并交换消息。当我使用 socket.close() 与客户端断开连接然后尝试重新连接时,就会出现问题。然后服务器在 g_io_channel_unix_new() 调用中崩溃。这是为监听来自新客户端的数据而创建的 channel 。我尝试取消引用最后使用的客户端的 io_channel 但这没有帮助。有人可以阐明这个问题吗?相关代码如下

            gboolean
            read_socket (GIOChannel *in, GIOCondition condition, gpointer data)
            {
                gint got=0, ret=0;
                char message[256]={'\0'};

                char *handShakeReply = NULL, *reply = NULL; 
                char *p=NULL;
                HandshakeParams hsParams;
                unsigned long key1=0, key2=0;
                unsigned char resultKey[16]={'\0'};

                gint local_client_socket = g_io_channel_unix_get_fd(in);

                if(condition & G_IO_HUP)
                {
                  printf("\nUnexpected Broken pipe error on client_fd\n");
                  close(local_client_socket);
                  return FALSE;
                }


                memset(message,0,256);
                memset(&hsParams, 0, sizeof(HandshakeParams));

                if(isHandShakeDone==0)
                {
                printf("\nHandshaking..\n");

                got = recv (local_client_socket, message, 256, 0);

                    if (got < 0)
                {
                       printf("Failed to read from socket");
                       /*TRUE becasue we still want GmainLoop to monitor this eventsource, the socket*/
                       return TRUE;
                }

                printf("GOT MESSAGE:\n%s\n", message);

                collect_handshake_params(message, &hsParams);

                handShakeReply = (char*)malloc(1024); 
                memset(handShakeReply, 0, 1024);
                p = handShakeReply;

                strcpy(p,   "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a");
                p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a");  
                strcpy(p, "Upgrade: WebSocket\x0d\x0a"); 
                p += strlen("Upgrade: WebSocket\x0d\x0a");
                strcpy(p,   "Connection: Upgrade\x0d\x0a");
                p += strlen("Connection: Upgrade\x0d\x0a");
                strcpy(p, "Sec-WebSocket-Origin: ");
                p += strlen("Sec-WebSocket-Origin: ");
                strcpy(p, hsParams.origin);
                p += strlen(hsParams.origin);
                strcpy(p,   "\x0d\x0aSec-WebSocket-Location: ws://");
                p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
                strcpy(p, hsParams.host);
                p += strlen(hsParams.host);
                strcpy(p, "/mySession\x0d\x0a");
                p += strlen("/mySession\x0d\x0a");
                strcpy(p,   "\x0d\x0a");
                p += strlen("\x0d\x0a");



                if((ret=interpret_key(hsParams.key1,&key1)) < 0)
                   {
                 printf("\nError in parsing key1! Errcode=%d\n",ret);
                 return FALSE;
                   } 
                   else
                   {
                 printf("\nStripped Key1 = %ld\n", key1);
                   }

                   if((ret=interpret_key(hsParams.key2,&key2)) < 0)
                   {
                 printf("\nError in parsing key2! Errcode=%d\n",ret);
                 return FALSE;
                   } 
                   else
                   {
                 printf("\nStripped Key2 = %ld\n", key2);
                   }

                   //Arrange in Network Byte Order!
                   resultKey[0] = key1 >> 24; 
                   resultKey[1] = key1 >> 16;
                   resultKey[2] = key1 >> 8;
                   resultKey[3] = key1;
                   resultKey[4] = key2 >> 24;
                   resultKey[5] = key2 >> 16;
                   resultKey[6] = key2 >> 8;
                   resultKey[7] = key2;

                   memcpy(&resultKey[8], hsParams.key3, 8);

                   copyMD5Hash(resultKey, (unsigned char *)p);
                   p += 16;

                   printf("\nHandshake Reply:\n%s\n", handShakeReply);

                   ret = send(local_client_socket, handShakeReply, p-handShakeReply, 0);
                   if(ret < 0)
                   {
                 perror("\nError in sending handshake reply:");
                   }
                   else
                   {
                 isHandShakeDone=1;
                   }

                   free(handShakeReply);
                   p=NULL;
                   free_handshake_params(&hsParams);

                }
                else
                {
                   printf("\nServing Client..\n");

                   getClientRequest(local_client_socket, message);

                   if(message[0] == '\0')
                   {
                  /*Close this connection for this client instance and wait for connection from the next instance of client*/

                  close(local_client_socket);

            #if 0   
                  GIOStatus status;          
                  GError *error=NULL;

                  status = g_io_channel_shutdown(in,TRUE,&error);
                  if(status==G_IO_STATUS_NORMAL)
                  {
                     printf("\nClient IO channel shutdown was normal\n");
                  }
                  else
                  {
                    printf("\nIO channel shutdown status: %d\n", status);
                  }


                  /*Unref twice since g_io_add_watch() increases the reference count too*/
                  g_io_channel_unref(in);
                  g_io_channel_unref(in);
            #endif     

                  isHandShakeDone=0;
                  return TRUE;
                   }

                   reply = (char*)malloc(256); 
                   memset(reply, 0, 1024);
                   p = reply;

                   *p = 0;
                   p++;

                   strcpy(p,"This is the server's reply!");
                   p += strlen("This is the server's reply!");

                   *p = 255;
                   p++;

                   ret = send(local_client_socket, reply, p-reply, 0);
                   if(ret < 0)
                   {
                 perror("\nError in sending response:");
                   }

                }

                return TRUE;

            }



            gboolean
            handle_socket(GIOChannel *in, GIOCondition condition, gpointer data)
            {
               GIOChannel *client_channel;
               gint client_socket;

               gint socket_fd = g_io_channel_unix_get_fd(in);

               if(condition & G_IO_HUP)
               {
                 printf("\nUnexpected Broken pipe error on socket_fd\n");
                 close(socket_fd);
                 return FALSE;
               }

               if(isHandShakeDone==0)
               {

                   client_socket = accept (socket_fd, NULL, NULL);

                   if (client_socket < 0)
                   {
                      g_print("ERROR CLIENT_SOCKET VALUE!!!!!!!!!!!!!!!!!!!!");
                      return FALSE;
                   }


                   client_channel = NULL;


                  /*Program crashes on this call*/
                   client_channel = g_io_channel_unix_new (client_socket);
                   g_io_channel_set_encoding (client_channel, NULL, NULL);
                   g_io_channel_set_buffered (client_channel, FALSE);


                   g_io_add_watch (client_channel, G_IO_IN | G_IO_HUP, (GIOFunc) read_socket, NULL);
               }

               return TRUE;
            }

            int main(int argc, char **argv)
            {

               GIOChannel *channel_socket;
               gint socket_fd;
               static GMainLoop *loop = NULL;
               struct sockaddr_in serv_addr;

               g_type_init();

               isHandShakeDone=0;

               socket_fd = socket (AF_INET, SOCK_STREAM, 0);
               if (socket_fd < 0) 
               {
                 g_print("Error creating socket\n");
                 exit (1);
               }

               bzero((char *) &serv_addr, sizeof(serv_addr));

               serv_addr.sin_family = AF_INET;
               serv_addr.sin_port = htons(49059);
               serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

               if (bind (socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
               {
                 g_print("Error binding socket");
                 exit(2);
               }

               listen (socket_fd, 5);

               channel_socket = g_io_channel_unix_new (socket_fd);
               g_io_channel_set_encoding (channel_socket, NULL, NULL);
               g_io_channel_set_buffered (channel_socket, FALSE);

               g_io_add_watch (channel_socket, G_IO_IN | G_IO_HUP, (GIOFunc) handle_socket, NULL);

               g_print("GOING INTO MAINLOOP\n");

               loop = g_main_loop_new (NULL, FALSE);
               g_main_loop_run (loop);
         }

这是 GDB 回溯:

(gdb) bt
 #0  0x002c983e in ?? () from /lib/tls/i686/cmov/libc.so.6
 #1  0x002cbff6 in ?? () from /lib/tls/i686/cmov/libc.so.6
 #2  0x002cdf9c in malloc () from /lib/tls/i686/cmov/libc.so.6
 #3  0x001bf244 in g_malloc () from /lib/libglib-2.0.so.0
 #4  0x001fb4ac in g_io_channel_unix_new () from /lib/libglib-2.0.so.0
 #5  0x08049b01 in handle_socket (in=0x8051f60, condition=G_IO_IN, data=0x0) at          test_server.c:498
 #6  0x001faefb in ?? () from /lib/libglib-2.0.so.0
 #7  0x001b65e5 in g_main_context_dispatch () from /lib/libglib-2.0.so.0
 #8  0x001ba2d8 in ?? () from /lib/libglib-2.0.so.0
 #9  0x001ba817 in g_main_loop_run () from /lib/libglib-2.0.so.0
 #10 0x08049ce4 in main (argc=1, argv=0xbffff344) at test_server.c:551
 (gdb) 

最佳答案

@HungryTux,您回答了自己的问题,但仅供引用,您可以

memset(reply, 0, sizeof(reply))

#define REPLY_SIZE 256
reply = (char*)malloc(REPLY_SIZE);                     
memset(reply, 0, REPLY_SIZE); 

通常,代码中应该出现的唯一数字是 0、1、-1,偶尔也出现 2。

几乎任何其他东西都应该是一个符号!

关于c - 当客户端尝试重新建立连接时,g_io_channel_unix_new() 调用会导致 SIGSEGV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5311582/

相关文章:

c - 我无法通过 g_hash_table_look_up() 获得结果

c# - Owin Websockets - 了解 IOwinContext 和 WebSocketAccept

google-cloud-platform - Google Cloud Speech API的异步问题

python - 使用 Django Channels 将信息发送到所有连接的客户端

C:存储和读取ipv4/ipv6地址和端口

c - 排序篮球运动员名字的函数

c - 使用 glib 将数据写入文件

c - c中的结构默认值

c - 指针 - 困惑

linux - 使用 "gcc $(pkg-config --cflags --libs glib-2.0) context.c"编译时出错 -> <galloca.h> 未找到