《Unity3D網絡遊戲實踐》(第2版)要點摘錄 - 「Tcp深入了解」
書名:****《Unity3D網絡遊戲實踐》(第2版)
作者:羅培羽
所讀版本:機械工業出版社
4層網絡模型
- 應用層
- 應用程序層面
- 把數據轉換成二進制流傳給傳輸層(Socket.Send)
- 傳輸層
- 對數據進行加工,並提供各種功能
- 雙端約定收到信息後會給對方回應,確保信息的傳遞成功
- 代表了TCP/IP中的「TCP」
- 「IP」為網絡層
- 「TCP」是在網絡層協議的基礎上,增加了數據拆分、確認重傳、流量控制的機制
- 數據拆分
- 為每個數據添加了20個字節的頭部信息,包含了「數據的編號」
- 數據拆分
- 對數據進行加工,並提供各種功能

- 網絡層
- 「IP」給傳輸層(TCP)數據添加上具體的目的地/本地的地址信息
- 網絡接口
- 數據通過物理介質進行傳輸和解析
數據傳輸流程(TCP)
連接建立
-
TCP是面向連接的,在發送數據前,雙方之間必須建立連接
- A發送一封特殊信件(SYN)至B => B收到後回應一封(SYN/ACK)信件至A,此時A知道連接可達
-
三次握手
- 初始化連接,同步連接雙方的序列號、確認號、交換TCP窗口的大小信息
- 連接方調用Connect,向監聽方發送數據包(SYN)
- SYN包含了序列號seq
- 監聽方收到SYN數據包後,由標志位SYN知道對方正在請求建立連接;然後將SYN/ACK數據包發送回去以確認連接請求
- 連接方收到SYN/ACK數據包後,Connect函數返回,連接成功;然後將ACK數據包發至監聽方
- 假如Connect一直沒返回,代表底層正在等待和嘗試重發SYN或SYN/ACK數據包,直到連接成功/超出重試次數
- 當監聽方收到ACK包,將連接狀態設為established時,代表連接成功建立

數據傳輸
- 發送數據時,TCP會考慮對方緩沖區的容量,當對方緩沖區滿時,會暫停發送數據,防止對端溢出
- 發送一個數據後,發送方不能確保數據被對方接收,發送方會等待接收方的回應
- 如果太長時間沒有收到回應,發送方會重新發送數據
- TCP會根據數據返回的時間判斷網絡是否擁堵,是則減慢發送的速度
連接終止
-
四次揮手
- 確保雙端釋放socket資源
- 主機1向主機2發送終止信號(FIN),主機1進入FIN_WAIT_1狀態,沒有需要發送的數據,等待主機2回應
- 主機2收到主機1發送的終止信號(FIN),向主機1回應1個ACK;收到ACK的主機1進入FIN_WAIT_2狀態
- 主機2把所有數據發送完畢後,向主機1發送終止信號(FIN),請求關閉連接
- 主機1收到主機2發送的終止信號(FIN),向主機2回應1個ACK,然後主機1進入TIME_WAIT狀態;主機2收到ACK後關閉連接
- TIME_WAIT:等待一段時間,處理主機2的重發數據

常用TCP參數
- ReceiveBufferSize
- 指定OS接收緩沖區的大小,默認為8192字節
- SendBufferSize
- 指定OS發送緩沖區的大小,默認為8192字節
- NoDelay
- 是否使用Nagle算法(true為不使用)
- 對程序頻繁發送數據量很小的數據進行優化
- 讓這些數據累積到一定數量再組成一個大數據包發送出去
- 優點:減少數據量
- 缺點:降低了實時性
- 是否使用Nagle算法(true為不使用)
- TTL
- 發送的IP數據包的生存時間值(Time To Live)
- IP頭中的一個值,表示一個IP數據報能夠經過的最大路由器跳數(默認值與OS相關,xp = 128, win7 = 64, win10 = 65, linux = 255)
- 目的是避免IP在網絡中的無限循環收發

- ReuseAddress
- 端口複用,讓同一個端口可被多個socket使用
- 目的:由於退出程序與釋放端口兩者是不同步的,因此,重啟服務器時,可能會因為端口還沒被釋放而導致端口綁定失敗;直到端口被釋放後才能成功重啟
- LingerState
- 設置socket保持連接的時間
- 客戶端發起斷開連接的請求後,服務端會向客戶端發送一個FIN信號
- 該信號讓客戶端進入TIME_WAIT狀態
- 該狀態目的是讓服務端在斷開連接前處理未完成的事情
- 通過LingerState來指定該等待時間
- 時間==0,一直等待,直到發送完
- 時間>0,等待指定時間後斷開連接
- 設置socket保持連接的時間
心跳機制
-
斷開連接時,主動方會給對端發送FIN信號,開啟4次揮手流程;若主動方無法給對端發送FIN信號,對端會一直認為連接有效
-
TCP自帶一個檢測機制,如果在指定時間內沒有數據傳送,會給對端發送一個信號;對端如果收到,回送一個TCP信號;如果一段時間沒有收到響應,重試幾次仍失敗則視為網絡不通,關閉socket
-
Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true)
-
-
心跳機制思路
- 客戶端定時向服務端發送Ping消息
- 服務端收到後回應Pong消息,並記錄客戶端最後一次發送Ping消息的時間
- 如果服務端很久沒有收到Ping,就假定連接不通,關閉連接並釋放socket資源