shutdown与close函数的区别

有时候代码中需要连续多次调用write,可能还来不及调用read得知对方已关闭了连接就被SIGPIPE信号终止掉了,这就需要在初始化时调用sigaction处理SIGPIPE信号,对于这个信号的处理我们通常忽略即可,signal(SIGPIPE, SIG_IGN);如果SIGPIPE信号没有导致进程异常退出(捕捉信号/忽略信号),write返回-1并且errno为EPIPE。

close函数

#include <unistd.h>
int close(int fd);

close 关闭了自身数据传输的两个方向。

shutdown函数

#include <sys/socket.h>
int shutdown(int sockfd, int how);

shutdown可以选择关闭某个方向或者同时关闭两个方向,shutdown how = 0 or how = 1 or how = 2 (SHUT_RD or SHUT_WR or SHUT_RDWR)。

shutdown可以保证对等方接收到一个EOF字符,即发送了一个FIN段,而不管其他进程是否已经打开了这个套接字。而close不能保证,只有当某个sockfd的引用计数为0,close才会发送FIN段,否则只是将引用计数减1而已。也就是说只有当所有进程(可能fork多个子进程都打开了这个套接字)都关闭了这个套接字,close才会发送FIN段。

如果是调用shutdown how = 1
,则意味着往一个已经发送出FIN的套接字中写是允许的,接收到FIN段仅代表对方不再发送数据,但对方还是可以读取数据的,可以让对方可以继续读取缓冲区剩余的数据。

if (FD_ISSET(fd_stdin, &rset))
{

    if (fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
    {
        stdineof = 1; //表示已经输入完毕
        /* 关闭sock的写端,还能够接收数据 */
        shutdown(sock, SHUT_WR);
    }
    else
    {
        writen(sock, sendbuf, strlen(sendbuf));
        memset(sendbuf, 0, sizeof(sendbuf));

    }
}

select阻塞等待时发现套接字的读端已经关闭,不能再关心可读事件了,select会返回-1,错误码是 EBADF: Bad File Descriptor