《Unity3D網絡遊戲實踐》(第2版)要點摘錄 – 「Tcp深入了解」Reading Notes, Developing, Unity3D網絡遊戲實踐 / By LoneliNerd / 2022 年 9 月 27 日 2022 年 10 月 16 日 書名:《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為不使用)對程序頻繁發送數據量很小的數據進行優化讓這些數據累積到一定數量再組成一個大數據包發送出去優點:減少數據量缺點:降低了實時性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,等待指定時間後斷開連接 心跳機制斷開連接時,主動方會給對端發送FIN信號,開啟4次揮手流程;若主動方無法給對端發送FIN信號,對端會一直認為連接有效TCP自帶一個檢測機制,如果在指定時間內沒有數據傳送,會給對端發送一個信號;對端如果收到,回送一個TCP信號;如果一段時間沒有收到響應,重試幾次仍失敗則視為網絡不通,關閉socketSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true)心跳機制思路客戶端定時向服務端發送Ping消息服務端收到後回應Pong消息,並記錄客戶端最後一次發送Ping消息的時間如果服務端很久沒有收到Ping,就假定連接不通,關閉連接並釋放socket資源