1. 三次握手

握手主要流程:
Client -> Server: SYN x = rand()Client Client -> Server: ACK x+1, y+1
注意:隻有在一次完整的 roundtrip 之後 Client 才能開始發送資料;Server 則需要收到 ACK x+1, y+1 消息到達後才能開始發送資料。
TCP Fast Open
- 打開此配置時,可以第一條
消息裡帶上資料,不用等一次完整的 roundtrip
SYN
- 限制:
消息中可帶的資料大小有限制
SYN
- 隻有特定的幾種 HTTP 請求可使用此方式發送
- 隻能用于重複連接配接之前曾經連過的 Server 的情況下
- 配置:
- Server: Linux kernel v4.1+
- Client: iOS 9+/OSX 10.11+ 或他相應的 Linux 版本
- 應用程式打開相關的 socket flag
- 性能提升:
- HTTP網絡延遲降低 15%
- 頁面加載時間平均降低 10%
- 某些高延遲情況下有 40% 的降低
2. 擁塞控制
1) 限流(Flow control)
- 目的:防止一端發送過多資料使另一端來不及處理
- 機制:
- 用戶端、服務端分别告知對方已方接收視窗的大小(rwnd)
- 連接配接剛建立時,兩端的 rwnd 都使用系統預設值
- 每個 ACK 消息都會帶上目前最新的 rwnd,使對方可以動态調整發送的資料流量
Window Scaling (RFC 1323)
- 目的:TCP協定隻為rwnd預留了16位,使rwnd最大為2^16=65536位元組,要想設定超過此值的的視窗大小,需要 Window Scaling
- 實作:在三次握手過程中确定一個左移位數(shift),rwnd 的實際大小為ACK消息中帶的16位的值左移 shift 以後得到的值
- 支援 Window Scaling 以後,rwnd 最大支援1G位元組
- 主流系統上已預設開啟
- 通信信道上的中間結點、路由器、防火牆等可能會禁用此選項
$> sysctl net.ipv4.tcp_window_scaling $> sysctl -w net.ipv4.tcp_window_scaling=1
2) 擁塞控制(Congestion control)
- 目的:防止發送太多資料導緻網絡來不及處理導緻網絡擁塞
- 慢啟動(Slow-Start)
- Server側為每個 tcp 連接配接維護一個擁塞視窗大小(cwnd),其預設的初始值比較小。
- cwnd 不需要通知對端
- 為提高傳輸效率,可将 cwnd 預設初始值提高到10個 network segments
- 引入規則:傳輸中未被 ACK 的資料量限額為 MIN(cwnd, rwnd)
- 開始時 cwnd 較小,随後每收到一個 ACK,cwnd += 1,這樣下次就可以發送之前兩倍的資料量
- 擴充:Slow-Start Restart 機制
- 連接配接空閑一段時間後會将 cwnd 重設為預設值
- 為防止此機制影響連接配接的傳輸性能,可采用下列指令關閉此機制:
$> sysctl net.ipv4.tcp_slow_start_after_idle$> sysctl -w net.ipv4.tcp_slow_start_after_idle=0
- Server側為每個 tcp 連接配接維護一個擁塞視窗大小(cwnd),其預設的初始值比較小。
- 擁塞避免(Congestion avoidance)
- 網絡條件好的情況下,cwnd會一直倍增,直到其超出接收方系統配置的擁塞門檻值視窗大小(ssthres),或出現丢包。此時會觸發擁塞避免機制來調整擁塞視窗(cwnd)大小
- 常見算法:
- TCP Tahoe and Reno
- TCP Vegas
- TCP New Reno
- TCP BIC
- TCP CUBIC (Linux上預設)
- Compound TCP (Windows上預設)
- Proportional Rate Reduction for TCP (RFC 6937)
- 目的:加快丢包後的恢複速度
- 性能:在有丢包的連接配接上平均延時降低3-10%
- Linux 3.2+ 核心上預設使用此擁塞避免算法
3. 隊頭阻塞
TCP
協定下每個資料包都有唯一的序号,協定能夠保證這些包的可靠、按順序傳輸。但如果多個包中某個序号比較靠前的在傳輸過程中發生了丢包,其它序号靠後的包即使已順利到達,也需要在接收方的緩沖區中等待,直到隊頭包重傳成功才能将封包組裝并傳回給應用層。
- 隊頭阻塞發生在
協定層,應用層無法感覺,應用層隻能感覺到總體的傳輸延遲TCP
- 隊頭阻塞的負面影響在音、視訊應用這種不要求所有包都到達即可正常運作的場景下尤其明顯。
4. 四次揮手
Client -> Server: SEQ=x, FIN=1 //Client=FIN_WAIT1Client : SEQ=y, ACK=x+1 //Client=FIN_WAIT2, Server=CLOSE_WAITClient : 可能有 Server 還未發完的資料傳送繼續進行...Client : SEQ=z, ACK=x+1, FIN=1 //Server=LAST_ACKClient -> Server: SEQ=x+1, ACK=z+1 //Client=TIME_WAIT(2MSL後自動進入CLOSED狀态)
參考資料
- https://hpbn.co/building-blocks-of-tcp/