【问题标题】:Program received signal SIGPIPE, Broken pipe程序接收信号SIGPIPE,Broken pipe
【发布时间】:2013-09-26 22:39:42
【问题描述】:

我编写了一个基于 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;
}

它是什么以及做什么?

【问题讨论】:

标签: c sockets gdb pthreads sigpipe


【解决方案1】:

进程收到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

【讨论】:

  • 这行得通吗? if(signal(SIGPIPE, signalHandler) == EINVAL) 我怎么会得到错误-1和EPIPE。
  • @Dreyfus15:要澄清有关如何设置信号处理程序的不确定性,请在此发布另一个问题。
【解决方案2】:

使用 'gdb' 进行调试时,可以手动禁用 SIGPIPE,如下所示:

(gdb) 处理 SIGPIPE nostop

【讨论】:

  • 其实是handle SIGPIPE nostop noprint pass
  • 这将终止程序而不是在 gdb 中停止(除非程序忽略 SIGPIPE 或为其安装处理程序,根据接受的答案)。
【解决方案3】:

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);

【讨论】:

  • 您的 SIGPIPE 信号处理程序将消息写入标准输出。但是假设写入标准输出是首先导致 SIGPIPE 的原因......?
  • 在信号处理程序中使用不可重入标准输出是不安全的。
  • 确实,如果您在处理程序中执行 printf(),您必须担心可重入代码。但是看到这只是一个例子,我觉得 printf() 很好,只需抛出一个信号(SIGPIPE, SIG_DFL);在 printf() 之前,你应该没问题。
【解决方案4】:

您已写入已被对等方关闭的连接。

【讨论】:

    【解决方案5】:

    我遇到了同样的问题,它让我看到了这个 SO 帖子。我收到零星的 SIGPIPE 信号,导致我的由 nginx 运行的 fastcgi C 程序崩溃。我尝试signal(SIGPIPE, SIG_IGN); 没有运气,它一直在崩溃。

    原因是nginx的临时目录有权限问题。修复权限解决了 SIGPIPE 问题。 Details here on how to fixmore here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      • 2022-10-31
      • 2023-03-30
      • 2018-06-08
      • 2017-03-28
      相关资源
      最近更新 更多