异步信号导致套接字I / O问题

时间:2012-08-01 05:48:38

标签: c sockets pthreads signals mutex

我正在一个多线程环境中的客户端 - 服务器应用程序。客户端和服务器都有两个线程。主线程使用套接字(IPv4-TCP)发送数据,客户端的相应主线程恢复数据send和recv函数是自定义函数,作为我设计的一部分。我在另一个线程中为服务器上的SIGUSR1,SIGUSR2和SIGINT设置了三个信号处理程序。接收到SIGINT后,完成线程清理以正常关闭所有套接字并终止线程,在接收SIGUSR1,SIGUSR2时,我设置两个全局标志,在同一个线程中使用,并在主线程中使用自定义发送函数做一些将套接字ID切换到IPv6的操作。(有一些逻辑让客户端知道套接字已更改为IPv6)。自定义发送/ recv函数具有malloc和free函数。

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

主题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;
}

1 个答案:

答案 0 :(得分:0)

感谢大家的回复。经过一些进一步的研究,我发现SIGUSR1是由主线程而不是控制线程处理的。由于调用的fn_recv具有类似malloc,free的函数,我认为它不是可重入的,它导致了问题。

我通过屏蔽SIGUSR1信号并创建一个单独的线程来设置信号处理程序而不是控制线程来解决它,以避免干扰系统/函数调用。我在新线程中取消屏蔽SIGUSR1信号,以确保它仅由这个新线程处理。 我现在能够传输数据并多次切换套接字ID而没有停顿。 如果有人需要更多细节,请告诉我。 基本上屏蔽主线程中的信号并在子线程中解锁它就行了!