2012-08-01 115 views
0

我正在多线程环境中处理客户端 - 服务器应用程序。客户端和服务器都有两个线程。主线程使用套接字(IPv4-TCP)和客户端对应的主线程recvs数据。send和recv函数是自定义函数,作为我设计的一部分。我在服务器的SIGUSR1,SIGUSR2和SIGINT的另一个线程中设置了三个信号处理程序。在收到SIGINT后,线程清理完成,以正常关闭所有套接字并终止线程,在收到SIGUSR1,SIGUSR2时,我设置了两个用于同一线程中的全局标记和主线程中的自定义发送函数来执行一些操作关于将套接字ID切换到IPv6的操作(有一种逻辑可以让客户端知道套接字变为IPv6)。自定义send/recv函数具有malloc和free函数。引发套接字I/O问题的异步信号

问题是当我在终端上使用kill -SIGUSR1 pid向服务器进程发送信号后,发送一些呼叫后,发送挂起。对于每次发送的呼叫,我发送的数据包有数据大小要发送,实际数据和一个可选标志来指示下一个数据将在另一个套接字ID上。当我在客户端打印数据大小时,在接收到信号后,在某些recv调用之后它全部为零。我确信SIGNAL必须是原因,因为当我反转操作并让客户端将数据发送到服务器时(上载)使用相同的send/recv函数,它工作正常。我可以切换套接字ID。在这两种情况下,我都将信号发送到服务器进程。recv函数一直保留,直到数据量与TCP数据流的大小部分中指示的数量相同。 我不确定为什么在接收信号后的一些发送调用后size变为零。我已经使用了互斥体,其中使用了全局变量,除了信号处理程序部分设置时。代码如下。

线程2:

fn_sigUsrHandler(SIGUSR1); 
fn_sigUsrHandler(SIGUSR2); 
fn_sigUsrHandler(SIGINT); 
void fn_sigUsrHandler(int p_signal) 
{ 
/* Signal handler structure */ 
struct sigaction vl_sigStruct; 
int vl_errno; 
char vl_err_buff[256]; 

vl_sigStruct.sa_flags = SA_RESTART; 
sigemptyset(&vl_sigStruct.sa_mask); 


switch(p_signal) 
{ 
    case SIGUSR1: 
     vl_sigStruct.sa_handler = fn_switch; 
     break; 
    case SIGUSR2: 
     vl_sigStruct.sa_handler = fn_switch; 
     break; 
    case SIGINT: 
     vl_sigStruct.sa_handler = fn_cleanUP; 
     break; 
} 

vl_errno = sigaction(p_signal, &vl_sigStruct, NULL); 
if (vl_errno == -1) { 
    fprintf(stdout,"Control Thread-Error in catching SIGUSR1:%s\n",fn_strerror_r(errno,vl_err_buff)); 
    exit(EXIT_FAILURE); 
} 


void fn_switch(int st_val){ 
/* 
pthread_mutex_lock(&socket_mutex_3); 
ip_proto_switch = 1; 
vg_ctrlpacket_sent =1; 
pthread_mutex_unlock(&socket_mutex_3); 
*/ 

vg_proto_switch = 1; 
vg_ctrlpacket_sent =1; 

fprintf(stdout,"Signalled to switch\n"); 
} 

主线程:

int vl_err; /* Number of bytes sents */ 
char err_buff[256]; /* Buffer to hold error message*/ 
int vl_change_sock = 0; 

if(p_flags != NO_DATA_TX) 
{ 
    char *vl_bufData; 
    st_packetData vst_packet; /* Structure holding the data to be sent */ 
    unsigned int vl_packetSize = sizeof(unsigned int) +  sizeof(vst_packet.vst_pad) + (int)p_len;//sss 
    vl_bufData = (char *)malloc(vl_packetSize); 
    memset(vl_bufData,'\0',vl_packetSize); 

    pthread_mutex_lock(&socket_mutex_2); 
     if(vg_ctrlpacket_recv == 1){ 
      ///strcpy(vst_packet.vst_pad,vg_change_socket); 
      vl_change_sock = 1; 
      vg_ctrlpacket_recv = 0;     
      fprintf(stdout,"len:%d\n",strlen(vst_packet.vst_pad)); 
     } 
    pthread_mutex_unlock(&socket_mutex_2); 


    if(vl_change_sock == 1){ 


      char *vl_bufData2 = vl_bufData+sizeof(unsigned int); 
      snprintf(vl_bufData2,(int)p_len,"%s",p_buffer); 
      //memcpy(vl_bufData+sizeof(unsigned int)+(int)p_len,vg_change_socket,sizeof(vst_packet.vst_pad));//sss 
     */ 

     snprintf(vl_bufData,sizeof(unsigned int)+1,"%u",vl_packetSize); 
     memcpy(vl_bufData+sizeof(unsigned int),p_buffer,(int)p_len);//sss 
     snprintf(vl_bufData+sizeof(unsigned int)+(int)p_len,sizeof(vst_packet.vst_pad)+1,"%s",vg_change_socket); 

     vl_err = send(p_mysocket->socket_id,vl_bufData,vl_packetSize,p_flags); 
     if(vl_err == -1) 
     { 
      fprintf(stderr,"mysocket-fn_send-TCP-vl_err err :%s\n",fn_strerror_r(errno,err_buff));//HS 
      exit(EXIT_FAILURE);//HS 
     } 

     if(debug > 0) 
      fprintf(stdout,"The socket before change is :%d client side \n",p_mysocket->socket_id); 

     if((p_mysocket->socket_id) == p_mysocket->sock_id[0]) 
      p_mysocket->socket_id = p_mysocket->sock_id[1]; 
     else 
      p_mysocket->socket_id = p_mysocket->sock_id[0]; 

     if(debug > 0) 
      fprintf(stdout,"The socket after change is :%d client side \n ",p_mysocket->socket_id); 

    } 
    else{ 
     snprintf(vl_bufData,sizeof(unsigned int)+1,"%u",vl_packetSize); 
     memcpy(vl_bufData+sizeof(unsigned int),p_buffer,(int)p_len);//sss 

     vl_err = send(p_mysocket->socket_id,vl_bufData,vl_packetSize,p_flags); 
     if(vl_err == -1) 
     { 
      fprintf(stderr,"mysocket-fn_send-TCP-vl_err err :%s\n",fn_strerror_r(errno,err_buff));//HS 
      exit(EXIT_FAILURE);//HS 
     } 

    } 

    if(debug > 2){ 
     /*fprintf(stdout,"size of st_packetData:%d\n",sizeof(st_packetData)); 
     fprintf(stdout,"vl_packetSize:%d\n",vl_packetSize); 
     fprintf(stdout,"Memcopied-data:%s\n",vst_packet.vst_data); 
     fprintf(stdout,"Memcopied-pad:%s\n",vst_packet.vst_pad); 
     fprintf(stdout,"Memcopied-size:%d\n",vst_packet.vst_size);//sss 
     fprintf(stdout,"Data from buffer:%s\n",p_buffer); 
     fprintf(stdout,"data:%s\n",vl_bufData+sizeof(vst_packet.vst_size)+sizeof(vst_packet.vst_pad));*/ 
     fprintf(stdout,"Copied data:%-10.6s\n",vl_bufData); 
     fprintf(stdout,"---------------------------\n"); 
    } 


    //if(vl_err >=(sizeof(vst_packet.vst_size)+ sizeof(vst_packet.vst_pad))) //sss 
    if(vl_err >=(sizeof(unsigned int)+ strlen(vg_change_socket))) 
    { 
     vl_err = vl_err-(sizeof(unsigned int) + strlen(vg_change_socket));//sss 
    } 
    if(debug > 2) 
    { 
     fprintf(stdout,"The socket id is :%d.. Thread:%s\n",p_mysocket->socket_id,p_mysocket->vst_nm_thread); 
     fprintf(stdout,"The data tx %d.. Thread:%s\n",vl_err,p_mysocket->vst_nm_thread); 
    } 

    free((void *)vl_bufData); 

} 
else 
{ 
    vl_err = send(p_mysocket->socket_id,p_buffer,p_len,0); 
    if(vl_err == -1) 
    { 
     fprintf(stderr,"mysocket-fn_send-TCP-vl_err err :%s\n",fn_strerror_r(errno,err_buff));//HS 
     exit(EXIT_FAILURE);//HS 
    } 
    if(debug>1) 
    { 
     fprintf(stdout,"The socket id is :%d.. Thread:%s\n",p_mysocket->socket_id,p_mysocket->vst_nm_thread); 
     fprintf(stdout,"The data tx %d.. Thread:%s\n",vl_err,p_mysocket->vst_nm_thread); 
    } 
} 
/* return number of bytes sent */ 
return vl_err; 
} 
+0

您是否尝试过在调试器中运行它以查看它挂起的位置? – 2012-08-01 06:41:23

+0

我还没有尝试任何调试器。我不确定任何适用于多线程环境的调试器。请咨询 – user369823 2012-08-02 04:16:01

+1

如果您在信号处理程序中设置了一个断点,您应该能够看到每个线程停止的位置,并且在该语句之后的任何线程中设置一个新的断点,然后从该断点逐步逐行执行。所有现代调试器(如所有Linux发行版都可以使用的standrad GDB)都知道,并且可以处理线程。 – 2012-08-02 05:24:37

回答

0

感谢所有您的答复。在进一步研究之后,我发现SIGUSR1是由主线程处理的,而不是控制线程。由于被调用的fn_recv具有像malloc一样的功能,因此我认为free是不可重入的,这导致了问题。

我通过屏蔽SIGUSR1信号并创建一个单独的线程来设置信号处理程序而不是控制线程来解决这个问题,以避免干扰系统/函数调用。我在新线程中屏蔽了SIGUSR1信号,以确保它仅由此新线程处理。 我现在可以传输数据并多次切换套接字ID而不会出现停顿现象。 如果有人需要更多的细节,请让我知道。 基本上在主线程中屏蔽信号并在子线程中取消它的做法诀窍!