linux – 套接字,TCP状态和写入系统调用
我一直在使用一个简单的服务器,它每30秒向一个客户端发送一个心跳包,然后通过心跳回复包确认心跳.当我通过发送SIGKILL,SIGSEGV来粗暴地终止服务器时,客户端通过select()和read()系统调用很容易发现它.然后我开始想知道当你在客户端写入其心跳回复数据包之前这样做会发生什么,所以我在客户端代码中放置了20秒的睡眠并且同时杀死了服务器但发现客户端写入仍然成功.紧接着尝试第二次写入会触发预期的SIGPIPE信号并写入返回的EPIPE.据我所知,这是正常行为,但出于好奇,我打印出了客户端tcp状态.结果是:
> TCP_ESTABLISHED – 在发送服务器SIGKILL之前. 所以我的问题是: >为什么第一次写入不会引发SIGPIPE并返回EPIPE? 正如我现在所理解的那样,正在发生的事情的图表: 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 解决方法
TCP是异步的.您的只写将数据复制到套接字缓冲区并返回. TCP堆栈在后台接管并用于发送该数据.换句话说,当send / sendmsg / write返回时,并不意味着数据尚未发送. 当服务器被杀死时,内核会在你的套接字上关闭,发送未完成的数据,然后是FIN,这会将你的客户端套接字置于TCP_CLOSE_WAIT状态.它是一个半开连接状态,客户端仍可以发送数据,前提是服务器需要它. 您的客户端发送更多数据,但服务器操作系统使用RST响应,因为没有处理传入数据的进程.这会将您的客户端套接字置于TCP_CLOSE中.
TCP_CLOSE是最终的TCP状态.不确定您要问的是什么,但如果您需要确保其他对等方接收并处理了您的数据,则需要发回一些应用程序级别的消息. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |