客戶端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沒有收到連接其實沒有建立成功。不知道這個解釋各位看官是否滿意_