【发布时间】:2014-09-01 02:08:54
【问题描述】:
我一直在使用一个简单的服务器,它每 30 秒向客户端发送一个心跳包,然后客户端通过心跳回复包确认心跳。当我通过发送 SIGKILL、SIGSEGV 来残酷地终止服务器时,客户端很容易通过 select() 和 read() 系统调用发现这一点。然后我开始想知道当您在客户端写入其心跳回复数据包之前执行此操作时会发生什么,所以我在客户端代码中设置了 20 秒的睡眠时间并同时终止了服务器,但发现客户端写入仍然成功。之后立即尝试第二次写入会触发预期的 SIGPIPE 信号并写入返回的 EPIPE。然而,据我所知,这是正常行为,只是出于好奇,我打印了客户端 tcp 状态。结果是:
- TCP_ESTABLISHED - 在发送服务器 SIGKILL 之前。
- TCP_CLOSE_WAIT - 在第一次客户端写入之前的服务器端 SIGKILL 之后。
- TCP_CLOSE - 在第一次和第二次写入尝试之后。
所以我的问题是:
- 为什么第一次写入不引发 SIGPIPE 并返回 EPIPE?
- 如果在第一次写入后 TCP 状态为 TCP_CLOSE 是否可以断定与服务器的连接已关闭,或者我是否必须再重新发送一次数据才能确定?
目前我所理解的正在发生的事情的图表:
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
【问题讨论】: