代码之家  ›  专栏  ›  技术社区  ›  Phuah Yee Keat

写(2)仍然报告成功,即使我已经关闭了套接字

  •  0
  • Phuah Yee Keat  · 技术社区  · 15 年前

    测试程序如下:

    我期待第二次写入返回SIGPIPE,但它返回了成功,只有第三次写入返回SIGPIPE!为什么会这样?

    #include <stdio.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdarg.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <signal.h>
    
    void log_error(const char *fmt, ...) 
    {
     va_list ap;
     char buf[BUFSIZ] = {0};
    
     va_start(ap, fmt);
     vsnprintf(buf, BUFSIZ, fmt, ap);
     fprintf(stderr, "ERROR: %s\n", buf);
     va_end(ap);
     return;
    }
    
    static int create_inet_socket()
    {
        int fd;
        struct sockaddr_in my_addr;
        int yes = 1;
    
        if ((fd=socket(PF_INET, SOCK_STREAM, 0))==-1) {
     log_error("create_inet_socket:socket:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))==-1) {
     log_error("create_inet_socket:setsockopt:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons(9998);
        my_addr.sin_addr.s_addr = INADDR_ANY;
        memset(&(my_addr.sin_zero), '0', 8);
    
        if (bind(fd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr_in))==-1) {
     log_error("main:bind:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        if (listen(fd, 5)==-1) {
     log_error("main:listen:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        return fd;
    }
    
    int myconnect()
    {
        int fd;
        char ch[1] = {'a'};
        struct sockaddr_in sin;
        fd_set wfds;
        struct timeval tv;
        struct hostent *he;
        ssize_t nwritten;
    
        if ((fd=socket(PF_INET, SOCK_STREAM, 0))==-1) {
     log_error("rlog:socket failed:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        bzero(&sin, sizeof(sin));
    
        if ((he=gethostbyname("localhost"))==NULL) {
     log_error("rlog:gethostbyname failed:%d:%s", errno, strerror(errno));
     return -1;
        }
    
        sin.sin_addr = *((struct in_addr*)he->h_addr);
        sin.sin_port = htons(9998);
        sin.sin_family = AF_INET;
    
        if (connect(fd,(struct sockaddr *) &sin,sizeof(sin)) == -1) {
     log_error("connect:%d:%s", errno, strerror(errno));
     return 0;
        }
    
        nwritten = write(fd, &ch, 1);
        if (nwritten==-1) {
     log_error("write:%d:%s", errno, strerror(errno));
        } else {
     fprintf(stderr, "client : 1. written %ld\n", nwritten);
        }
        sleep(3);
        nwritten = write(fd, &ch, 1);
        if (nwritten==-1) {
     log_error("write:%d:%s", errno, strerror(errno));
        } else {
     fprintf(stderr, "client : 2. written %ld\n", nwritten);
        }
        sleep(3);
        nwritten = write(fd, &ch, 1);
        if (nwritten==-1) {
     log_error("write:%d:%s", errno, strerror(errno));
        } else {
     fprintf(stderr, "client : 3. written %ld\n", nwritten);
        }
        return 0;
    }
    
    void run_server()
    {
        int fd;
        int newfd;
        char c[1];
        ssize_t nread;
        int status;
        fprintf(stderr, "server : Running\n");
        fd = create_inet_socket();
        if (fd==-1) {
     perror("create_inet_socket");
        }
    
        newfd = accept(fd, NULL, NULL);
        fprintf(stderr, "server : accepted newfd %d\n", newfd);
    
        nread = read(newfd, &c, 1);
        if (nread==-1) {
     log_error("read:%d:%s", errno, strerror(errno));
        } else {
     fprintf(stderr, "read returned %ld, closing socket\n", nread);
        }
        shutdown(newfd, SHUT_RDWR);
        close(newfd);
        wait(&status);
        fprintf(stderr, "server : exit\n");
    }
    
    void run_client()
    {
        fprintf(stderr, "client : running\n");
        myconnect();
        fprintf(stderr, "client : exit\n");
        _exit(1);
    }
    
    int main()
    {
        signal(SIGPIPE, SIG_IGN);
        int pid = fork();
        switch (pid) {
        case 0:
     run_client();
     break;
        case -1:
     perror("fork");
     break;
        default:
     run_server();
     break;
        }
        return 0;
    }
    
    
    1 回复  |  直到 10 年前
        1
  •  4
  •   Nikolai Fetissov    15 年前

    你不能仅仅依靠 write(2) -这是连接两端之间的一个大竞争条件(内核缓存您提供给系统调用的数据,数据包需要时间来通过连接等),因此在传输级连接中断的情况下引入了数据丢失的可能性。如果您需要可靠性,请设计应用程序级协议,以便接收方确认所有数据。

    The ultimate SO_LINGER page or why is my TCP not reliable ,但目前似乎是下跌。谷歌的标题,它可能是镜像的地方。