TCP長連接的一些事兒


1、TCP的特點以及與應用

       TCP提供一種面向連接的、可靠的字節流服務。面向連接意味着兩個使用TCP的應用(通常是一個客戶和一個服務器)在彼此交換數據包之前必須先建立一個TCP連接。TCP建立連接需要經過三次握手,首先,客戶端發送一段報文給服務器,表示我要連你,服務器收到報文后馬上回復客戶端,同意或者不同意你連我,最后客戶端再發送一段報文給服務器表示確認要連接,經過這三次握手,客戶端才能最終連接上服務器。TCP主要有這幾個特點:TCP是面向連接的傳輸層協議;每個TCP連接只能有兩個端點,而且只能是一對一通信,不能一點對多點直接通信;數據以字節流的方式傳輸;傳輸的數據無消息邊界;TCP通過丟包重傳、滑動窗口、數據排序、擁塞控制等機制來保證傳輸數據的可靠性。
       一般,強聯網類型的游戲都使用TCP,當然,有些對實時性要求很高的游戲也會將TCP與UDP配合使用,比如王者榮耀這類MOBA游戲,在實時戰斗中會使用可靠UDP協議,來保證游戲數據的高效傳輸,弱聯網類型的一般使用HTTP,HTTP為短鏈接,它基於TCP協議,當完成一次通訊就會馬上斷開連接。
 

2、如何維護一個長連接

       在游戲過程中,玩家所處的網絡環境是復雜多變的,有時因為糟糕的網絡問題,會出現客戶端掉線、延遲、丟包等問題,網絡狀況不好時UDP會丟包嚴重,TCP雖然是可靠,但也會在ip層丟包,只不過由於TCP的重傳機制,能保證數據能傳輸到遠程終端,但也會造成延遲。那么如何維護好一個長連接呢?那就是做好斷線重連機制。
什么時候觸發斷線重連?
        第一種判斷方法:在網絡糟糕的情況下,在客戶端進行網絡操作時經常會顯示的拋出異常,比如NetworkException、Timeout等,這種情況下,就說明客戶端已經無法與服務器通訊,這時就需要客戶端主動發起對服務器連接。
        第二種判斷方法:使用心跳檢測,可以服務器定時發心跳包給客戶端,也可以客戶端定時發心跳包給服務器,我認為最穩妥的應該是客戶端發送心跳包給服務器,服務器收到后再回復一條確認收到的消息給客戶端,心跳包只需簡單設計就好,一般只包含消息頭,不含消息體。當超過規定時間T沒有收到心跳返回包時,就觸發斷線重連。
        第三種判斷方法:使用Keepalive,keepalive是在TCP中一個可以檢測死連接的機制,是由TCP協議層實現的,具體使用方法我暫時也沒去了解~
        第四種判斷方法:當手機客戶端切回后台后一定時間又返回游戲,或者網絡連接從wifi切到4G等情況下,可以主動觸發一次重連操作。
斷線重連的大致流程:        

3、如何處理粘包分包問題

       使用TCP協議做網絡模塊開發時,由於TCP本身的機制,如果發送的數據很小,那么會自動把一些小的數據合並在一起發送出去,但是接收端就沒辦法理解數據包並自行分開它,這就是粘包現象;而當一次發送的數據又過長的時候,TCP就會把該數據分成幾部分發送出去,每次接收方就只會接受部分的數據,這就是分包現象。由於粘包和分包現象是在傳輸層發生的,我們只能在應用層想辦法解決,處理粘包和分包有很多方法,這里介紹幾種常見的方法:
       第一種方法是在每個數據包前面加上該數據包的長度,作為該數據包的包頭,當收到消息包時,先讀取消息包頭,得到消息包的長度,再根據這個長度去讀取對應長度的字節,這樣就能很好的解決粘包分包的問題。
       第二種方法是在每個消息包的頭部或尾部加上一個標識符,這個標識符不能是常用的字符,比如可以使用‘¥’這類平時不會出現在消息體中的字符,將它作為消息包界限,接收端在收到消息后就能根據這個界限方便的去做處理。
       第三種方法是如果使用的是JSON這類字符串做傳輸,可以根據消息包的首尾字符,通過判斷首尾‘{’和‘}’來組成一個完整的消息包。
 

4、使用TCP還是UDP

       眾所周知,C/S架構中,TCP使用廣泛,UDP同樣也有不少用武之地,先看一下UDP與TCP相比的區別:首先,UDP速度比TCP快,因為UDP不需要先與對方建立連接,也沒有傳輸確認這一步驟,因此其速度會快不少;UDP一次性發送一個消息包,不需要考慮消息邊界的問題;UDP可以使用廣播或者組播的方式進行一對多傳輸;UDP由於沒有可靠的消息傳輸機制,它的可靠性不如TCP,也不能保證有序傳輸。
       游戲往往對數據的可靠性傳輸要求很高,似乎看起來只能使用TCP,然而,很多游戲對客戶端數據同步要求特別高,比如英雄聯盟和王者榮耀,使用TCP來傳輸實時戰斗數據是行不通的,那還是只能在UDP上想辦法 ,通過對UDP進行一層可靠性封裝,可以使UDP同樣具有類似TCP傳輸可靠有序的特點。英雄聯盟開發時使用的是Enet,ENet提供一個相對簡單的以及穩健的位於UDP頂部的網絡通信層。其提供的主要功能是可選的可靠按順序的傳送數據包。王者榮耀使用的似乎是KCP,KCP是一個快速可靠協議,它主要的設計目的是為了解決在網絡擁堵的情況下TCP協議網絡速度慢的問題,增大網絡傳輸速率,但相當於TCP而言,會相應的犧牲一部分帶寬。KCP沒有規定下層傳輸協議,一般用UDP作為下層傳輸協議。提供類似這種可靠UDP服務的還有UDT等,在GitHub上可以找到不少這類項目。
 

5、使用哪種網絡傳輸數據格式

       在做客戶端服務器通訊前,要選擇一種網絡傳輸數據格式,在做選擇時,都需要考慮幾點:第一是數據大小,這關系到占用帶寬和傳輸效率,應該盡量不要有多余的數據;第二點是可拓展性、可維護性,必須支持序列化及反序列化消息中用到的數據結構;第三點是數據安全性,有些數據是敏感數據,需要進行加密處理;第四點是是否跨平台支持;第五點是消息可讀性,這點不重要,但消息可讀性高的話,調試時方便。
       游戲開發中,主要的網絡傳輸數據格式有Json、Xml、Protobuf,以及自定義二進制數據包,在很多時候,我們都使用Json和Xml,因為使用簡單,可讀性高,調試方便,但它們屬於文本,占用空間稍大,顯得有些臃腫。自定義二進制數據格式雖然體積小,傳輸高效,但致命的缺點是可擴展性差,在編寫和解析數據包時很容易出錯,而且當需要編寫一些數據結構時會比較麻煩,因此這種方式只適合小項目。Protobuf是一種輕便高效的結構化數據存儲格式,Protobuf可用於通訊協議、數據存儲等領域的語言無關、平台無關、可擴展的序列化結構數據格式,目前提供了C++、Java、Python、C#等多種語言的API,很適合用於網絡游戲的消息結構體定義上。相對於XML文件和Json文件,它的性能更好,效率更高。
 
如有錯誤,歡迎指正!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM