欧美经典成人在观看线视频_嫩草成人影院_国产在线精品一区二区中文_国产欧美日韩综合二区三区

聚惠wifi碼小程序(小程序,獨立搭建,現成系統)

聚惠wifi碼小程序(小程序,獨立搭建,現成系統)

蒙寄 2025-06-28 科技 22 次瀏覽 0個評論

  

  第一部分 一個普通的網絡模塊

  大部分項目對網絡的需求都比較簡單。主要需要滿足登錄、購買、顯示背包物品等低頻的協議請求。面對這部分需求,只要一個普通的網絡模塊就可以搞定。

  我們就先從這一部分開始,編寫一個普通的網絡模塊。

  1

  模塊設計

  1.1

  重要

  網絡模塊的重要性,無須多言。

  1.2

  神秘

  一個項目的模塊很多,但是網絡模塊只有一個。再結合網絡模塊的重要性,所以,大部分新來的同學,都沒有機會做網絡模塊。

  兩個項目的背包模塊幾乎無法相同,但是網絡模塊卻幾乎通用。繼續結合網絡模塊的重要性,所以一個項目的網絡模塊大概只會在——曾經做過網絡模塊的同學——手里不斷重構和完善,最后幾乎可以與業務無關。于是,大部分已經工作一段時間的同學,再也沒有機會做網絡模塊。

  我遇到很多新老同學過來打聽網絡模塊的情況。大家覺得它很神秘,躍躍欲試,卻不知從何入手。

  現在就有一個機會,我們一起來設計和實現一個網絡模塊。

  1.3

  簡單

  其實網絡模塊沒有什么神秘。它的一般性框架是這樣的(火影手游的PVP網絡模塊是專用的網絡模塊,詳見我之前的文章,以及后續的教程):

  

  圖1 網絡模塊的一般性框架

  看起來好像很簡單,大致就分為兩大部分:連接管理器和協議管理器。而且這兩個管理器的實現也相當簡單。大致如下:

  

  圖2 連接管理器與協議管理器的實現

  ConnectManager。它維護一個Connection實例列表。這些實例根據底層通訊接口的不同,有多種類型。Connection封裝了數據的收發邏輯,它分別為Send和Receive提供Buffer。它主要實現以下功能:

  創建連接。

  這部分功能主要在XXConnection類實現,不同的通訊接口,連接方式不同。比如Apollo的通訊接口,需要提供公司的一攬子參數。而Bluetooth接口而需要提供BluetoothMacAddress。而采用底層的Socket實現的UDP通訊接口,則無須Connect過程,那么我們就給它虛擬一個假的Connect過程,以保持IConnection接口的統一性。等等等等。

  收發數據。

  大部分通訊接口對數據的Recv是通過輪詢實現的,在ConnectManager里將輪詢操作統一轉換為事件方式。

  斷線重連。

  Connection分別為Send和Recv提供了Buffer,以便支持靜默重連,使上層邏輯在大部分情況下無須關心網絡是否斷開,也可以發送數據。比如,網絡突然斷開了,假設A模塊不負責維護在線狀態,那么在它看來,它依然可以正常發送數據。假設B模塊負責維護在線狀態,那么它應該監聽到網絡斷開,然后進行重連,最后重連成功。在網絡重連成功后,緩存在Connection的數據,就可以發送出去了。整個過程,對A模塊是不可感知的。(是不是覺得斷線靜默重連也沒有想像中那么復雜了?)

  ProtocolManager。相對ConnectManager,它簡單得多。它維護一個從協議ID到協議類的映射(對于C#這種具有反射機制的語言,可以直接映射到協議類,但是對于C++則可以用其它方法來實現映射)。并且定義了協議格式。

  到此為止,一個幾乎通用的網絡模塊框架基本上搭完了。是不是很簡單?

  1.4

  模塊糖

  模塊糖,這是我杜撰的一個詞。就像語法糖一樣。對于不同的項目,可以給ConnectManager和ProtocolManager加一些糖,讓它用起來更甜。比如將SendProtocol(pid, PTLObj, connId)包裝成SendDirProtocol(pid,PTLObj)和SendZoneProtocol(pid,PTLObj)等;將CreateConnection(connId,type,ip,port)包裝成CreateDirConnection(ip,port)和CreateZoneConnection(ip,port)等。Dir和Zone在網絡模塊中的含義大家應該都知道。

  等等等等。

  2

  連接層實現

  上面聊了一下網絡模塊的一般性框架。下面從具體實現來聊聊相關技術。掌握了這些技術點,便可以輕松實現一個網絡模塊的連接層。

  2.1

  關于Socket

  Socket就是常說的套接字。說實話我對這個翻譯是很懵逼的。Socket就是我們正常網絡編程中能夠接觸到的最底層的通訊接口。對于它的原理,在這篇文章中,我們只意會,不言傳。

  對于Socket,我們最需要關注的是它的工作方式。在客戶端Socket主要有2種工作方式:

  同步方式。無論是UDP還是TCP,在用Socket進行連接、發送、接收的時候,在未完成工作前代碼不再繼續往下執行,處于等待狀態,直到該語句完成對應個工作后才繼續執行下一條語句。值得注意的是,UDP和TCP對于一件工作是否完成的定義不同,以Send為例,如下圖。

  對于TCP來說,未完成工作就是:

緩沖區滿了,數據無法寫入,

或者數據寫入了但是還沒輪到它發送,

或者數據發送了,但是未收到ACK確認。

  對于UDP來說,未完成工作就是:緩沖區滿了,數據無法寫入。

  

  圖3 Socket同步方式時序圖

  異步方式。即不論對應工作是否完成,都會繼續往下執行。當工作完成后,是通過一個回調來通知調用者(千萬注意:這個回調是在一個Socket內部創建的子線程上下文中)。參照上圖,不需要單獨用時序圖來說明了。

  在同步方式中,可以理解為有一個Loop在不停地輪詢是否完成工作,直到工作完成才結束Loop。為了避免UI以及主邏輯被卡住,一般需要將以同步方式工作的操作都放在自制的子線程中。而在異步方式中,實質上是Socket內部創建了一個子線程。

  那么綜合以上情況,在實際使用中,我們應該選擇“同步方式”還是“異步方式”呢?我做的不完全性能測試的結論是,同步方式的性能大概是異步方式的4倍。這是很容易理解的,因為這里所謂的異步方式其實就是Socket內部幫我們做了一個線程,而且它為了考慮到基礎組件的通用性,肯定在性能方面會有所損耗。

  看看下表的對比:

  對比

  同步方式

  異步方式

  性能

  高

  低

  復雜度

  自制線程

  內置線程

  靈活性

  高

  低

所以,如果對網絡連接沒有特別要求的情況下,比如獨立小游戲,可優先考慮異步方式,省心省事。但是,我更愿意使用同步方式+

自制線程

,對于系列性能更加可控。

  2.2

  關于多線程

  當我們不得不使用子線程時,就要面對一個令很多新同學都感到陌生神秘的東西:線程。由于使用多線程的情況并不多,所以主要掌握以下幾點大概便可以在網絡編程中使用多線程了。

  線程函數。

  如果說主線程是從Main函數開始的(在Unity+C#里,你是看不到Main函數的。),那么子線程也是從一個函數開始。為了防止主線程與子線程的代碼邏輯搞混,建議將線程函數定義在一個單獨的類里。由這個函數所調用的所有被調用函數都在這個類里。

  前臺線程和后臺線程。

  切記,系統默認創建的子線程是前臺線程,它將帶來一個問題,就是當主線程已經結束時,程序還會運行。如果將它設置為后臺線程,則當主線程結束時,所有后臺線程都會無異常中止。

  線程同步。

  當主線程和子線程存在共用數據時,為了避免多線程同時操作同一數據,需要使用“鎖”。C#有多種鎖定方式,比較常用的是lock語句。建議不要直接lock需要操作的數據,而是為這個數據定義一個對應的object,lock這個object。因為有些類型的數據,比如int,是無法直接lock的。

  異常處理。

  使用Try/Catch進行異常處理時,不要在線程的創建處TryCatch。一旦線程創建成功,線程執行過程中的異常,是無法在其它線程中被捕獲的。正確的做法是在線程函數里TryCatch。

  當然關于多線程的其它知識,有很多專門的文章介紹。

  2.3

  關于TryCatch

  對于C#來講,你使用或者不使用TryCatch,對于性能的消耗是一樣的。甚至你在離Exception最近的地方使用了TryCatch,還會提高性能。因為如果一當發生Exception,運行時會依次向上遞歸尋找TryCatch代碼,最終會找到運行時那一層去,然后成功被運行時Catch到。與其如此,為什么不自己去Catch呢?所以,應該積極地在適當的地方使用TryCatch,但是一定要在Catch后進行處理并且輸出日志,否則就隱藏了問題!

  2.4

  關于連接

  Connection是對底層或者基礎通訊接口以及可能使用的線程相關邏輯進行封裝。一般情況下,按照所使用的通訊接口類型進行封裝。

如果使用Apollo的通訊組件,可以封裝成ApolloConnection。

如果使用Socket,則封裝成TCPConnection/UDPConnection。

如果使用Bluetooth,則封裝一個BluetoothConnection。

如果使用RS232串口通訊,則封裝一個RS232Connection。

  這個世界上有很多種通訊方式,你都可以封裝成對應的Connection,以便統一它的通訊接口。除此之外,它主要還將提供Send和Recv的數據緩存。

  2.5

  關于數據包/數據流

  從圖1中,我們看到,一個“協議實例”將轉換為一個“協議數據包”,然后“協議數據包”將以“數據流/數據包”的形式發送出去。

  在不同的傳輸協議中,數據的發送形式是不同的。在TCP傳輸中,數據是以流的形式發送。而在UDP傳輸中,數據是以包的形式發送。

  它們的區別在于,一個數據包里包含一個協議的完整數據。而一段數據流里可能包含的是多個協議的數據,或者一個不完整的協議數據。

  2.6

  關于輪詢

  無論是使用同步方式還是異步方式,都會發生——主線程從子線程讀取數據——操作。有些同學喜歡采用拋事件的方式,但是,那樣只會使子線程的上下文擴散得更廣泛更亂。如果有一天你發生在一個事件的回調函數里調用Time.realtimeSinceStartup一直莫名其妙報錯,那么,這個回調函數一定是從一個子線程里調出來的。但是,你完全懵逼。

  所以,建議采用輪詢這種古老的方式,將子線程的上下文限制在一個輪小的范圍里。

  除了以上主要原因外,還有一個原因:

  異常隔離。防止業務層模塊異常導致整個Connection的異常。因為Connection作為基礎功能,還有其它模塊在使用。

  3

  協議層實現

  協議層相對連接層簡單得多。它的主要相關技術如下。

  3.1

  協議格式

聚惠wifi碼小程序(小程序,獨立搭建,現成系統)

  最基本的協議格式如下:

  協議頭

PID: 協議ID

Index: 協議發送序列號

DataBuffSize: 協議體的數據長度

CheckSum: 校驗和

  協議體

  DataBuff: 協議數據Buffer。

  以上協議格式定義了一個協議數據包。其中DataBuff來自對協議實例的序列化。

  為了實現對協議實例的序列化,我們可以自定義一個IProtocolBase接口,讓具體協議來實現這個接口。

  但是,在實際應用中,我們都是直接使用Google的ProtoBuf作為協議的基類。它已經提供了非常高效的序列化和反序列化功能。

  3.2

  協議流

  在章節2.4中得知,有些情況下,協議層收到來自連接層的數據,并不一定是一個恰好完整的協議數據包,而有可能一段數據流。于是,為了統一邏輯,不管收到的是數據包,還是數據流,我都將它們統一為協議流。

  在ProtocolManager中,需要對協議流進行合并或分割處理。其實很簡單,它的邏輯流程如下所示。(需要注意的是,如果系統中同時存在多個Connection,需要為每一個Connection定義一個協議流。)

  

  圖4 協議流處理邏輯

  3.3

  協議分類

  一般情況下,協議可以分為這幾類:

只發送,不需要監聽回包。用于向服務器上報數值。

無發送,只需要監聽回包。用于服務器Push數值,或者觸發邏輯。

一處發送,多處監聽回包。用于基礎功能協議。

一處發送,一處監聽回包。用于具體功能協議。

  ProtocolManager應該對上面4種協議都能提供支持。

  3.4

  協議ID規則

  后臺喜歡把協議ID叫CMD,或者CmdID。我一般直譯為PID。PID的規則一般有兩種:

  同一條協議,發包和回包時,PID相同。因為發包和回包時,雖然協議體內容不同,但卻是一回一答,是為同一個功能服務的。

  同一條協議,發包和回包時,PID不同。因為發包和回包時,協議體的內容不同。目前比較流行這種方式。為了使編程更方便,以及代碼容易理解,一般將回包的PID定義為發包的PID+1。

  4

  調試

  無論做什么模塊開發,都離不開調試。而網絡模塊對于調試的要求更高。可以這么說,你編寫一個網絡模塊可能需要2天,但是將來花在調試它的時間可能是直到項目結束。

  所以,在你完成網絡模塊的代碼編寫之后,一定不要忘記,為了能夠高效地調試,做好一切準備。

  4.1

  網絡日志系統

  我相信,你的項目中一定已經有了現成的日志系統。但是那遠遠不夠。建議在其基礎上封裝一個網絡日志系統,并且為它提供一個專用面板。它會比在總日志文本里看網絡日志要高效得多,性能也可控得多。它應該提供如下功能:

  單獨輸出網絡模塊的日志。

  以16進制顯示每一個Connection的Send和Recv緩沖區數據。這是你能夠接觸到的最底層接口的數據,后臺會經常和你Check這些數據。

  列出每一條被注冊的協議。

  記錄發送和接收到的每一條協議的內容。如果該協議是注冊的,則可以反序列化為結構性信息,如果未注冊,則提示未注冊,并且顯示16進制數據。

  統計斷線重連次數,斷線時長,網絡延時等。

  4.2

  網絡狀況模擬

  在研發階段,這個功能是非常有用的。可以幫助你高效測試網絡模塊在各種網絡情況下,是否正常工作。也可以為業務模塊提供網絡相關的測試手段。比如,測試在線模塊,斷線重連邏輯(再也不需要撥網線了)等。

  4.3

  抓包工具

  一般使用Wireshark和Fiddler。網絡編程必備工具。

  點擊一下

聚惠wifi碼小程序(小程序,獨立搭建,現成系統)

  立即閱讀相關好文章

《貪婪洞窟》談貪婪設計丨騰訊GAD游戲創新大賽丨

游戲美術3D設計干貨回顧丨為VR優化UE4渲染器丨

這么做設計才好玩丨Unity教程

MOBA類游戲核心設計分析

......

  近期熱文

  工作效率UP!Unity3D 手游版本構建之路

  新年送什么禮物給程序員男朋友,才能又走心又實用?

  

轉載請注明來自夕逆IT,本文標題:《聚惠wifi碼小程序(小程序,獨立搭建,現成系統)》

每一天,每一秒,你所做的決定都會改變你的人生!

發表評論

快捷回復:

評論列表 (暫無評論,22人圍觀)參與討論

還沒有評論,來說兩句吧...