Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1136646
  • 博文数量: 646
  • 博客积分: 288
  • 博客等级: 二等列兵
  • 技术积分: 5375
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-08 14:33
个人简介

为了技术,我不会停下学习的脚步,我相信我还能走二十年。

文章分类

全部博文(646)

文章存档

2014年(8)

2013年(134)

2012年(504)

分类:

2012-06-27 11:23:07

原文地址:捕捉SIGPIPE 作者:laoliulaoliu

环境:
Debian GNU/Linux 6.0
kernel 2.6.32-5-686 #1 SMP Wed Jan 12 04:01:41 UTC 2011 i686
gcc (Debian 4.4.5-10) 4.4.5

在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

所以我们需要对SIGPIPE信号进行捕捉,并且在系统函数(write,read,send,recv,etc..)收到此信号时,对错误(errno==EPIPE)进行处理。
下面是我对系统函数 write() 进行的测试:
 
ssize_t write(int fildes, const void *buf, size_t nbyte);
1. 如果遇到对方断开,进程就会自动悄无声息的退出。
2. 如果加入信号捕捉 signal(SIGPIPE, SIG_IGN); 或者 signal(SIGPIPE, processSignal); 则会不断出现write error: Broken pipe(这时可以做异常处理,来保证不会悄悄的退出)
tcpcli.c
C语言
#include
#include
#include
#include
#include
#include
#include

#define MAXBUF 4096000

void processSignal(int signo)
{
    printf("Signal is %d\n", signo);
    /* signal(signo, processSignal);
     * add this function again is an idea,but not right
     */ 
}

ssize_t writen(int fd, const void *vptr, size_t n)
{
    size_t        nleft;
    ssize_t       nwritten;
    const char    *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0{
        printf("Begin Writen %d\n", nleft);
        if ( (nwritten = write(fd, ptr, nleft)) <= 0{
            /* actually, this errno can't happen even if there is
             * a signal pipe */
            if (nwritten < 0 && errno == EINTR{
                printf("intterupt\n");
                nwritten = 0;        /* and call write() again */
            }
            else if (nwritten < 0 && errno == EPIPE{
                perror("pipe");
                return(-1);
            }
            else {
                perror("write error");
                return(-1);
            }
        }

        nleft -= nwritten;
        ptr += nwritten;
        printf("Already write %d, left %d, errno=%d\n", nwritten, nleft, errno);
    }
    return(n);
}

void str_cli(int sockfd)
{
    char    sendline[MAXBUF], recvline[MAXBUF];

    while (1{

        memset(sendline, 'a', sizeof(sendline));
        printf("Begin send %d data\n", MAXBUF);
        if ( sizeof(sendline!= writen(sockfd, sendline, sizeof(sendline)) )
            break;
        sleep(3);

    }
}

int main(int argc, char **argv)
{
    int                    sockfd;
    struct sockaddr_in    servaddr;

    //signal(SIGPIPE, SIG_IGN);
    signal(SIGPIPE, processSignal);

    if (argc != 2{
        printf("usage: tcpcli [port]\n");
        exit(0);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(argv[1]));
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    if (connect(sockfd, (struct sockaddr *&servaddr, sizeof(servaddr)) == -1)
    {
        perror("connect error");
        exit(1);
    }

    str_cli(sockfd);

    return 0;
}

也贴出server.c
C语言
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define MAXLEN 4096

int init_sock()
{
    int listenfd, listenq = 1024;
    struct sockaddr_in servaddr;

    if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
    {
        perror("socket error");
        return -1;
    }

    int optval = 1;
    if (setsockoptlistenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ) == -1)
    {
        perror("set socket reuse error");
        return -1;
    }

    /* block recv can't be used in non-block mode, or else 
     * error "Resource temporarily unavailable" will happen
     * if you want to set the socket in non-blocking mode, use
     * select() or poll()to see if there is incoming data before
     * calling recv() or recvfrom() */
    //struct timeval t_timeout;
    //t_timeout.tv_sec = 1;
    //t_timeout.tv_usec = 0;
    //setsockopt(listenfd, SOL_SOCKET, SO_SNDTIMEO, &t_timeout, sizeof(t_timeout));
    //setsockopt(listenfd, SOL_SOCKET, SO_RCVTIMEO, &t_timeout, sizeof(t_timeout));

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(9999);

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        perror("bind error");
        return -1;
    }
    
    if (listen(listenfd, listenq== -1)
    {
        perror("listen error");
        return -1;
    }

    return listenfd;
}

int main()
{
    int sockfd, connfd;
    char buff[MAXLEN];
    struct sockaddr_in cliaddr;
    socklen_t cliaddr_len = sizeof(cliaddr);

    if ( ( sockfd = init_sock() ) == -1 )
        exit(1);
    
    for(;;)
    {
        if ( (connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &cliaddr_len)) == -1 )
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
                ;
            else
                perror("accept error");
            continue;
        }

        if (fork() == 0)
        {
            /* If send, fill buffer can be wrapped to a function */
            //char *cli_addr = inet_ntoa(cliaddr.sin_addr);
            //memcpy(buff, cli_addr, MAXLEN);

            while (1)
            {
                if (recv(connfd, buff, MAXLEN, 0== -1)
                {
                    perror("recv error");
                    close(connfd);
                    exit(0);
                }
            }
        }

        if (close(connfd== -1)
        {
            perror("close error");
            continue;
        }

        waitpid(-1, NULL, WNOHANG);
    }
}
阅读(1513) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~