程序收到信号SIGPIPE,管道断开。

49

我基于POSIX套接字编写了一个客户端程序。该程序创建了多个线程并将锁定服务器。但是在使用GDB进行调试时,程序会给出一个信息(错误)。

(gdb) n
Program received signal SIGPIPE, Broken pipe. [Switching to Thread 0xb74c0b40 (LWP 4864)] 0xb7fdd424 in __kernel_vsyscall () 
(gdb) 
这里是代码:

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int get_hostname_by_ip(char* h , char* ip)
{
    struct hostent *he;
    struct in_addr **addr_list;
    int i;

    if ((he = gethostbyname(h)) == NULL) 
    {
        perror("gethostbyname");
        return 1;
    }
    addr_list = (struct in_addr **) he->h_addr_list;
    for(i = 0; addr_list[i] != NULL; i++) 
    {
        strcpy(ip , inet_ntoa(*addr_list[i]) );
        return 0;
    }

    return 1;
}

void client(char* h, int s)
{
    int fd;
    struct sockaddr_in addr;
    char ch[]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    fd = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family=AF_INET;
    char* ip = new char[20];
    get_hostname_by_ip(h, ip);
    addr.sin_addr.s_addr=inet_addr(ip);
    int port = 80;
    addr.sin_port=htons(port);
    if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
    {
        perror("connect error");
        return;
    }
    while(1)
    {
        if(send(fd, ch, sizeof(ch), 0) < 0)
        {   
            perror("send");
        }
    }
    //char buffer[1024];
    //if(recv(fd, &buffer, sizeof(buffer), 0) < 0)
    //{ 
    //  perror("recive");
    //}

    //printf("nReply from Server: %s\n", buffer);
    close(fd);
}

struct info
{
    char* h;
    int c;
};


void* thread_entry_point(void* i)
{
    info* in = (info*)i;
    client(in->h, in->c);
}

int main(int argc, char** argv)
{
    int s = atoi(argv[2]);
    pthread_t t[s];
    info in = {argv[1], s};
    for(int i = 0; i < s; ++i)
    {
        pthread_create(&t[i], NULL, thread_entry_point, (void*)&in);
    }
    pthread_join(t[0], NULL);

    return 0;
}

这是什么,该怎么做?


可能是[如何防止SIGPIPE(或正确处理它们)]的重复问题(https://dev59.com/RHVD5IYBdhLWcg3wDHDm)。 - iammilind
5个回答

68
该进程收到了一个SIGPIPE信号。这个信号的默认行为是结束进程。
如果进程尝试向已关闭写入或不再连接的套接字写入数据,则会向该进程发送一个SIGPIPE。
要避免程序在此情况下结束,您可以选择忽略SIGPIPE信号,或实现其它处理方式。
#include <signal.h>

int main(void)
{
  sigaction(SIGPIPE, &(struct sigaction){SIG_IGN}, NULL);

  ...
  • 安装一个明确的 SIGPIPE 信号处理程序(通常什么也不做):

  • 或者

    #include <signal.h>
    
    void sigpipe_handler(int unused)
    {
    }
    
    int main(void)
    {
      sigaction(SIGPIPE, &(struct sigaction){sigpipe_handler}, NULL);
    
      ...
    
    在这两种情况下,send*()/write() 将返回 -1 并将 errno 设为 EPIPE

    在这两种情况下,send*()/write() 将返回 -1 并将 errno 设为 EPIPE


    这样行吗?如果(signal(SIGPIPE, signalHandler) == EINVAL)我该如何获取错误代码-1和EPIPE。 - n0minal
    @Dreyfus15:为了澄清如何设置信号处理程序的不确定性,请发另一个问题。 - alk

    44
    在使用 'gdb' 进行调试时,可以通过以下方式手动禁用 SIGPIPE 信号:

    (gdb) handle SIGPIPE nostop


    20
    实际上,它是 handle SIGPIPE nostop noprint pass - Treviño
    这将终止程序而不是在gdb中停止(除非程序忽略SIGPIPE或为其安装了处理程序,如接受的答案所述)。 - Carlo Wood

    13
    一个避免处理 SIGPIPE 信号的方法是,使用以下代码忽略该信号:

    #include <signal.h>
    
    /* Catch Signal Handler functio */
    void signal_callback_handler(int signum){
    
            printf("Caught signal SIGPIPE %d\n",signum);
    }
    

    在你的代码中(主函数或全局作用域)

    /* Catch Signal Handler SIGPIPE */
    signal(SIGPIPE, signal_callback_handler);
    

    9
    你的SIGPIPE信号处理程序会将一条消息写入标准输出。但是,假设写入标准输出是导致SIGPIPE出现的原因,那该怎么办呢? - tetsujin
    6
    在信号处理程序中使用不可重入的stdio是不安全的。 - ulix
    如果在处理程序中使用printf(),确实需要担心可重入代码的问题。然而,既然这只是一个例子,我认为使用printf()是可以的,只需在printf()之前加上signal(SIGPIPE, SIG_DFL);就可以了。 - Paul Hutchinson
    或者你可以直接忽略它,而不提供任何虚假的处理程序,例如 signal(SIGPIPE, SIG_IGN); - ad3angel1s

    9
    您写入了一个已被对等方关闭的连接。

    5
    我曾经遇到过类似的问题,导致我的fastcgi C程序在nginx运行时出现间歇性的SIGPIPE信号,从而导致崩溃。我尝试使用signal(SIGPIPE, SIG_IGN);,但没有成功,它仍然会崩溃。
    原因是nginx的临时目录存在权限问题。修复权限问题解决了SIGPIPE问题。有关如何修复的详细信息,请参见此处此处

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接