1,只要client收到server的syn+ack,傳送ack,client就認為三次握手建立完成,狀態變為Established。阻塞的connect呼叫成功返回;對於非阻塞的connect呼叫,都會立馬返回,使用select、poll或者epoll機制來判斷socket是否可寫來判定連線是否建立。Established狀態下的client自然是可以傳送資料給server的。2,如果client的最後一個ack,中途丟失或者被server主動忽略或丟棄,server在定時器溢位後,會重發syn+ack,client向server傳送資料,server並不會返回Rst。要模擬這種場景,有兩種方式:1)收到server的syn+ack後,拔掉客戶端的網線;2)讓server端的accept佇列塞滿,主動丟棄ack。第一種場景模擬起來,難度比較大,於是我們採用第二種。我採用go寫的server來模擬。將net.core.somaxconn設定為2(因為go中listen呼叫,傳入的即為系統的上限制),方便模擬。
1,只要client收到server的syn+ack,傳送ack,client就認為三次握手建立完成,狀態變為Established。阻塞的connect呼叫成功返回;對於非阻塞的connect呼叫,都會立馬返回,使用select、poll或者epoll機制來判斷socket是否可寫來判定連線是否建立。Established狀態下的client自然是可以傳送資料給server的。2,如果client的最後一個ack,中途丟失或者被server主動忽略或丟棄,server在定時器溢位後,會重發syn+ack,client向server傳送資料,server並不會返回Rst。要模擬這種場景,有兩種方式:1)收到server的syn+ack後,拔掉客戶端的網線;2)讓server端的accept佇列塞滿,主動丟棄ack。第一種場景模擬起來,難度比較大,於是我們採用第二種。我採用go寫的server來模擬。將net.core.somaxconn設定為2(因為go中listen呼叫,傳入的即為系統的上限制),方便模擬。
客戶端傳送10個connect請求。測試結果中,反映了下面幾點:1)客戶端在傳送完ack後(13:48:52.999239),立馬(13:48:52.999879)開始傳送資料;2)傳送的資料超時後,開始重試;3)收到伺服器重發的syn+ack後,客戶端傳送ack;4)當伺服器的syn+ack重試次數超過系統設定值後,斷開連線,傳送Rst包給客戶端。結論:客戶端傳送完最後一個ack後,就認為連線建立,connect成功!3,accept成功?這個更簡單了,accept函式呼叫只是去accept佇列中取出一個連線而已,對伺服器而言,只要接收了客戶端的ack(注意,不忽略不拋棄哦),狀態變更為Established了,而不是accept呼叫成功才變成Established的。4,tcp的backlog佇列linux在實現tcp協議棧的時候,採用了兩個佇列,syn和accept佇列。當接收了對端的syn後,將其放入syn佇列;當接收了對端的ack後,將syn佇列中的連線轉移到accept佇列。5,如果backlog佇列滿了,咋辦?如果伺服器端Established了,但突然客戶端斷網了,伺服器進入半連線,咋辦?如果客戶端不停的傳送syn包咋辦?等等。。。很多問題。。這將會在我的淺析TCP(上) - 曹東的文章 - 知乎專欄 中篇中詳細介紹,敬請期待!