Program received signal SIGPIPE, Broken pipe原因总结,socket关闭测试总结

起源:

测试服务器时经常出现 signal SIGPIPE, Broken pipe,查看原因初步定位为客户端发起RST后导致。因此针对引起该信号的原因做了测试和总结。

过程:

UNIX网络编程卷1,第五章SIGPIPE节指出:当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。

根据上述描述能解释测试服务器出现的现象。

我实现了一个客户端服务器回射程序,测试后有两种情况会导致Broken pipe

1.客户端正常关闭socket,服务端连续两次write socket后出现

2.客户端RST关闭socket,服务端连续两次write socket后出现

3.客户端异常崩溃(实际就是发出RST),服务端连续两次write socket后出现

4.客户端RST关闭socket,服务端先read收到RST然后write socket后出现

 

客户端代码:

#include<stdio.h>
#include <sys/socket.h>   //connect,send,recv,setsockopt等
#include <sys/types.h>      

#include <netinet/in.h>     // sockaddr_in, "man 7 ip" ,htons
#include <poll.h>             //poll,pollfd
#include <arpa/inet.h>   //inet_addr,inet_aton
#include <unistd.h>        //read,write
#include <netdb.h>         //gethostbyname

#include <error.h>         //perror
#include <stdio.h>
#include <errno.h>         //errno

#include <string.h>          // memset
#include<stdlib.h>

#define ERR_EXIT(m)\
    do\
{\
    perror(m);\
    exit(EXIT_FAILURE);\
}while(0)

int main(void)
{
    int sock;
    if((sock =socket(AF_INET, SOCK_STREAM, 0))<0)
    {
        ERR_EXIT("ERROR");   
    }
    
   struct linger m_sLinger;
    m_sLinger.l_onoff=1;  //(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
   // 如果m_sLinger.l_onoff;0; 则功能和2.)作用相同;
   m_sLinger.l_linger=0;   //(容许逗留的时间为5秒)
//    setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&m_sLinger,sizeof(struct linger));

    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port = htons(8080);
    servaddr.sin_addr.s_addr = inet_addr("192.168.2.159");
    if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))< 0)
    {
      printf("errno=%d", errno);
      ERR_EXIT("connect");
    }
    char sendbuf[1024]={0};
    char recvbuf[1024]={0};
    while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
    {
     write(sock,sendbuf,strlen(sendbuf) -1);
     perror("ERROR1");

    // close(sock);
     read(sock,recvbuf,sizeof(recvbuf));
     printf("recvice: %s\n", recvbuf);
     perror("ERROR2");
     memset(sendbuf,0,sizeof(sendbuf));
     memset(recvbuf,0,sizeof(recvbuf));
     break;
    }
   
    close(sock);
    sleep(30);
    return 0;
}

服务端代码:

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

#include "errno.h"         

#define MAXLINE 1024

int main(int argc, char **argv)
{
  
  int listenfd, connfd;
  socklen_t clilen;
  struct sockaddr_in cliaddr, servaddr;
  
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(8080);
  bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
  printf("start listen\n");  
  listen(listenfd, 1024);
  
  for(;;){
    ssize_t n;
    char buf[MAXLINE];
    printf("maxline=%d\n", MAXLINE);
    clilen = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen);
    printf("new conn\n");

again:
    if((n = read(connfd, buf, MAXLINE)) > 0)
    {
       printf("readdata=%s, bytesnum=%d\n", buf, n); 
       sleep(5);
       int ret = write(connfd, buf, strlen(buf));    

      //write(connfd, buf, strlen(buf));    
       perror("ERROR2");
       printf("write first error, %d, err=%d\n", ret, errno);
    } 
    else if(n < 0)
    {
        if(errno == EINTR)
        {
          continue;
        }

       perror("ERROR3")
      write(connfd, buf, strlen(buf));
        break;
    }
    else if(n == 0)
    {
      perror("ERROR4");
      printf("write second error, %d, err=%d\n", n, errno);
     // read(connfd, buf, MAXLINE);
      write(connfd, buf, strlen(buf));
      write(connfd, buf, strlen(buf));
      perror("ERROR5");
      close(connfd);
      return 0;
    }
    
    goto again;
  
  }

  close(connfd);
  return 0;    
  
}

 

客户端中代码 setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&m_sLinger,sizeof(struct linger))代表close socket时发送RST,否则正常关闭socket.

 服务端代码n<0代表read时接收到RST,然后write会导致 Broken pipe,;n==0代表客户端正常关闭,连续两次write后都会出现Broken pipe

如果客户端write后直接close(注释代码),服务端read后n>0连续write(注释代码)会出现Broken pipe

 

试验过程中的另外一个结果:对于客户端正常close socket的,服务端第一次write返回写出字节数不会返回0,read会返回0.

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值