13-在TCP套接字上调用shutdown()
61.6.6 在TCP套接字上调用shutdown()
在前一节的讨论中我们假设完成的是全双工的关闭,那就是说,应用程序通过close()将 TCP 套接字的发送和接收通道都关闭了。如 61.2 节中所提到的,我们可以使用 shutdown()来只关闭连接的其中一个通道(半双工的关闭)。本节对 TCP 套接字上 shutdown()操作的一些细节之处做了说明。
在61.6.5节中我们谈到将参数how指定为SHUT_WR或者SHUT_RDWR时将开始TCP连接的终止步骤(即,主动关闭),而不管是否还有其他的文件描述符指向这个套接字。一旦终止步骤开始,本地 TCP 结点将迁移到 FIN_WAIT1 状态,然后进入 FIN_WAIT2状态,同时对端TCP结点将迁移到CLOSE_WAIT状态(见图61-6)。如果参数how指定为SHUT_WR,那么由于套接字文件描述符还保持合法,而且连接的读端仍然是打开的,因此对端可以继续发送数据给我们。
SHUT_RD在TCP套接字中是没有实际意义的操作。这是因为大多数TCP协议的实现中都没有为SHUT_RD提供所期望的行为,而且SHUT_RD产生的效果在不同的实现中各有不同。在Linux以及一些其他的实现中,在执行SHUT_RD操作后(在剩余的数据全部被读取完毕后),read()将返回文件结尾,这是我们对SHUT_RD操作所期望的行为,见61.2节的描述。但是,如果对端应用程序稍后在该套接字上写入数据时,那么仍然可能在本地套接字上读取到数据。
在其他一些实现中(例如BSD),SHUT_RD确实会导致后续的read()总是返回0。但是,在那些实现中,如果对端继续通过 write()向套接字写入数据,那么数据通道最终会被填满,直到对端的write()(阻塞式)被阻塞。(在UNIX域流式套接字中,如果在本地套接字上执行SHUT_RD操作后仍然继续向套接字上写入数据,那么对端将接收到SIGPIPE信号,且伴随的错误码为EPIPE。)
总的来说,对于可移植的TCP应用程序来说,应该避免使用SHUT_RD操作。