简体   繁体   English

写入关闭的套接字未按预期引发SIGPIPE

[英]writing to a close socket didn't raise a SIGPIPE as expected

I've already read about how to prevent SIGPIPE , then I write a small program to test it. 我已经阅读了有关如何防止SIGPIPE ,然后编写了一个小程序对其进行测试。 Here is the code. 这是代码。

server.c server.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

void hdl(int sig_num, siginfo_t *sig_info, void *context)
{
    printf("got you, SIGPIPE!\n");
}

int main()
{
    int sfd, cfd;
    struct sockaddr_in saddr, caddr;


    struct sigaction act;

    memset (&act, '\0', sizeof(act));
    act.sa_sigaction = hdl;
    act.sa_flags = SA_SIGINFO;

    if (sigaction(SIGPIPE, &act, NULL) < 0) {
        return 1;
    }

    sfd= socket(AF_INET, SOCK_STREAM, 0);
    saddr.sin_family=AF_INET;
    saddr.sin_addr.s_addr=inet_addr("192.168.22.91");
    saddr.sin_port=htons(12345);

    if(bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr)) )
    {
        printf("bind error\n");
        return -1;
    }
    if(listen(sfd, 1))
    {
        printf("error\n");
        return -1;
    }

    char buf[1024] = {0};
    while(1) {
            printf("Server listening...\n");
            cfd=accept(sfd, (struct sockaddr *)NULL, NULL);

            fcntl(cfd, F_SETFL, O_NONBLOCK);
            int size = read(cfd, buf, 1024);

            if(size == -1)
                printf("read error\n");

            sleep(2); // sleep for a while to make sure the client closed the socket

            int ret;
            if((ret = write(cfd, buf, strlen(buf)))<0)
            {
                if(errno == EPIPE)
                    fprintf(stderr, "SIGPIPE");
            }

            ret = write(cfd, buf, strlen(buf)); // write again.
            printf("write return %d\n", ret);
    }
    close(sfd);
}

client.c client.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <assert.h>


int main()
{
    int ret, fd;
    struct sockaddr_in sa_dst;
    char buffer[] = "hello, world";
    char rcv_buf[128] = {0};

    fd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&sa_dst, 0, sizeof(struct sockaddr_in));
    sa_dst.sin_family = AF_INET;
    sa_dst.sin_port = htons(12345);
    sa_dst.sin_addr.s_addr = inet_addr("192.168.22.91"); 

    ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
    if(ret != -1)
    {
        send(fd, buffer, strlen(buffer), 0);
        close(fd);
    }
    return 0;
}

When I run the server and the client on the same linux machine, on the server side, the first write() returns the number of bytes written while I expect a SIGPIPE signal because I closed the socket on the client side, the second write() does generate a SIGPIPE signal. 当我在服务器端的同一台Linux计算机上运行服务器和客户端时,第一个write()返回写入的字节数,而我期望一个SIGPIPE信号,因为我关闭了客户端的套接字,第二个write()确实会产生SIGPIPE信号。
But when I ran the client on another linux machine or on a Windows machine(implement the same client with Winsock), I did't catch any SIGPIPE signal, and the second write() still returns the size of the buffer . 但是,当我在另一台Linux机器或Windows机器(与Winsock实现相同的客户端)上运行客户端时,我没有捕获到任何SIGPIPE信号,第二个write()仍返回buffer的大小。 Can someone tell me what's going on? 有人可以告诉我怎么回事吗?

It can't happen on the first write, for two reasons: 它不能在第一次写入时发生,原因有两个:

  1. The localhost doesn't know that the peer has closed the socket for reading. 本地主机不知道对等方已关闭套接字以进行读取。 A FIN has been received but that could just be because the peer has shutdown for output. 已经收到FIN,但这可能仅是因为对等方已关闭以进行输出。 Only an RST will tell it that, and it doesn't get that util the next I/O at the earliest. 只有RST会告诉它,而且最早也不会利用下一个I / O。
  2. Buffering. 缓冲。

NB you're corrupting the value of errno by calling perror(), so testing it afterwards isn't valid. 注意,您通过调用perror(),破坏了errno的值perror(),因此事后对其进行测试无效。

Just Change this in SERVER and it will work 只需在SERVER中更改它,它将起作用

        fcntl(cfd, F_SETFL, O_NONBLOCK);
        int size = read(cfd, buf, 1024);

        if(size == -1)
            printf("read error\n");

        sleep(2); // sleep for a while to make sure the client closed the socket

        int ret;
           ret = write(cfd, buf, strlen(buf));
         sleep(2);
        ret = write(cfd, buf, strlen(buf)); // write again.
        printf("write return %d\n", ret);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM