我一直在使用一个简单的服务器,它每30秒向客户端发送一个心跳包,然后客户端用一个心跳应答包来确认心跳。当我通过发送SIGKILL残酷地终止服务器时,SIGSEGV客户端通过select()和read()系统调用就可以很容易地发现这一点。然后,我开始想知道当您在客户端写入其心跳应答包之前这样做会发生什么,所以我在客户端代码中放置了20秒的睡眠,同时关闭了服务器,但发现客户端编写仍然成功。尝试第二次写入之后,立即触发预期的SIGPIPE信号,并写入返回的EPIPE。据我所知,这是正常的行为,然而,出于好奇,我打印出客户端tcp状态。结果是:
所以我的问题是:
据我所知,目前正在发生的事情的图表:
server client
[ESTABLISHED] | | [ESTABLISHED]
SIGKILL or close () --> | |
[FIN_WAIT_1] |------------FIN M------------------->| [CLOSE_WAIT]
| | ---\
[FIN_WAIT_2] |<-----------ACK M+1------------------| |
| | | a read performed after a
[TIME_WAIT] |<-----------FIN N--------------------| [LAST_ACK?] |-- serverside SIGKILL returns 0
| | | but write succeeds
|------------ACK N+1----------------->| [CLOSE] |
| | ---/
| |
| | ---\
| | [CLOSE] | After the first write returns
| | | the TCP/IP state is CLOSED
| | [CLOSE] | but even so only the a second
| | | returns EPIPE and raises SIGPIPE.
| | [CLOSE] |
| | v 发布于 2014-07-10 16:08:51
为什么第一个写不提高SIGPIPE并返回EPIPE?
TCP是异步的。只将数据复制到套接字缓冲区并返回。TCP堆栈在后台接管,并负责发送该数据。换句话说,当send/sendmsg/write返回时,并不意味着数据已经发送。
当服务器被杀死时,内核会在套接字上为您执行close,然后发送未完成的数据,然后是FIN,这会使您的客户端套接字进入TCP_CLOSE_WAIT状态。它是半开放的连接状态,只要服务器需要,客户机仍然可以发送数据。
您的客户端发送更多数据,但是服务器操作系统使用RST进行响应,因为没有处理传入数据的进程。它将客户端套接字放入TCP_CLOSE中。
我是否可以得出结论,如果TCP状态在第一次写入到服务器的连接关闭后是TCP_CLOSE,还是必须再次重新发送数据才能确定?
TCP_CLOSE是最终的TCP状态。不确定您所要求的是什么,但是如果您需要确保其他对等方接收和处理您的数据,则需要发送一些应用程序级别的消息。
https://stackoverflow.com/questions/24680966
复制相似问题