客户端Write成功后再Read超时收到reset,服务器端显示连链接都没有建立?
当客户端第一次建立链接成功后,调用write向服务器发送请求,返回成功后调用read/recv等待回复却超时。
如果想搞清楚这个问题,需要掌握TCP三次握手,write系统调用到底是如何进行的。本文尝试一一阐述来解释这一怪现象。
TCP连接的建立-三次握手
TCP连接的建立大部分是三次握手的过程,传统的图如下:
客户端应用程序调用connect时会发起握手过程,看一下连接建立的点在哪里,如图,当Client收到ACK后connect返回,连接在Client端程序来看已经完成。但Server需要等待下一个ACK才算连接建立。
那么问题来了,如果最后一个ACK Server并没有收到,会有什么情况发生呢? 我们暂且悬疑,稍后作答。
Write系统调用成功代表报文送达了吗
不论是阻塞的或者非阻塞的socket,当向一个fd write的时候,实际上只是将用户态的一段内存拷贝到了内核态。换句话说,write成功返回并不代表对端已经收到,甚至都不说明报文已经送到了网络上。
看一下这幅图,调用write返回到报文送到网络上要经过多么复杂的流程吧:首先放置到tcp send buffer,经tcp协议栈,ip层,拥塞控制,DMA读写,然后一个中断才经网卡驱动发送出去。
所以,用户进程write返回后,几乎什么都代表不了,只是成功的发送到了内核态。听起来很悲剧。那么一个引申的问题就是,客户用户程序如何得知对端已经接收了上次发送的报文。答案就是从和server的通讯协议下手,即等待server回复一个类似确认的报文,很多rpc实现为一请求一应答其实是有根据的。
怪问题的答案
明白了上面两个问题之后,那么本文开始处的问题就不言而喻了。首先对于client来讲,用户程序认为connect建立成功,write虽然成功,但不能说明什么,而server由于最后一个ack没有收到连接其实没有建立成功。不知道这个解释各位看官是否满意_