TCP的那些怪事兒
客戶端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沒有收到連線其實沒有建立成功。不知道這個解釋各位看官是否滿意_
相關文章
- TCP 的那些事兒(下)TCP
- TCP 的那些事兒(上)TCP
- webpack的那些事兒Web
- Ubuntu的那些事兒Ubuntu
- https的那些事兒HTTP
- 面試的那些事兒--01面試
- Rest API 的那些事兒RESTAPI
- babel那些事兒Babel
- PHP那些事兒PHP
- OAuth那些事兒OAuth
- Git那些事兒Git
- 漏洞檢測的那些事兒
- 雲原生java的那些事兒Java
- HTTP 快取的那些事兒HTTP快取
- iOS 截圖的那些事兒iOS
- Android Drawable的那些事兒Android
- 聊聊viewport那些事兒View
- Java字串那些事兒Java字串
- Filebeat 收集日誌的那些事兒
- [apue] 等待子程式的那些事兒
- 聊聊瀏覽器的那些事兒瀏覽器
- JavaScript 中 setTimeout 的那些事兒JavaScript
- 七牛與 Ueditor 的那些事兒
- Weex 事件傳遞的那些事兒事件
- 關於 TCP 需要了解的事兒TCP
- C語言那些事兒C語言
- MySQL優化那些事兒MySql優化
- PHP 閉包那些事兒PHP
- 字元編碼那些事兒字元
- 網路安全那些事兒
- 依賴注入那些事兒依賴注入
- IT專案管理那些事兒專案管理
- Hadoop搭建那些事兒Hadoop
- powerbuilder 11的又一怪事UI
- Docker容器中應避免的那些事兒Docker
- 深入淺出Mysql索引的那些事兒MySql索引
- Elasticsearch(ES)分詞器的那些事兒Elasticsearch分詞
- 架構那些需要注意的事兒架構