网络游戏中网络模块浅析
在網(wǎng)絡(luò)游戲中,不論是服務(wù)端還是客戶端都需要網(wǎng)絡(luò)通訊的功能模塊,而一個(gè)優(yōu)秀的成熟的網(wǎng)絡(luò)通訊模塊,又可以用于多個(gè)游戲產(chǎn)品中。
?
于是,在學(xué)習(xí)的過(guò)程中,設(shè)計(jì)和實(shí)現(xiàn)一個(gè)可復(fù)用的網(wǎng)絡(luò)通訊模塊,變得非常的有意義。
?
???????? 通過(guò)思考我們可以一步一步的來(lái)實(shí)現(xiàn)這樣的模塊:
?
我們應(yīng)該知道對(duì)原生的Socket API進(jìn)行封裝是有必要的,也許當(dāng)前服務(wù)端是運(yùn)行在window環(huán)境下,也許改天就有可能要在Linux下面運(yùn)行。而對(duì)原生Socket API進(jìn)行封裝,可以很方便的讓我們進(jìn)行兩者的切換,并且不需要我們付出多大的代價(jià)。
可以像下面這樣封裝,放在SOCKET_API命名空間下面,其他API類似:
UINT SOCKET_API::recv_ex ( SOCKET s , void * buf , UINT len , UINT flags )
{
???????? #if defined __LINUX__
???? ???????? ….
#elif defined __WINDOWS__
???? ???????? ….
#endif
}
?
我們都知道游戲通常都是使用TCP來(lái)實(shí)現(xiàn)通訊的,而TCP需要下面這些最基本的功能及對(duì)SOCKET進(jìn)行設(shè)置或者獲取信息的函數(shù)。
| server | client |
| bind listen accept send recv close | connect send recv close |
我們希望把這些功能都封閉到一個(gè)CSocket類中。
class CSocket
{
public :
???? 構(gòu)造函數(shù),析構(gòu)函數(shù),初始化函數(shù)……
???? BOOL connect (const CHAR* host, UINT port) ;
????????????? UINT send (const VOID* buf, UINT len, UINT flags = 0) ;
???? SOCKET accept( struct sockaddr* addr, UINT* addrlen ) ;
其他函數(shù),例如receive ,bind,listen,close,get和set變量接口,有效性判斷等等……
public :
???? ???????? SOCKET m_SocketID;
???? ???????? SOCKADDR_IN m_SockAddr;
???? ???????? CHAR m_Host[IP_SIZE];
???? ???????? UINT m_Port;
}
不論是服務(wù)端還是客戶端都沒(méi)有辦法做到一收到消息就馬上響應(yīng)請(qǐng)求,然后直接把
這個(gè)消息丟棄掉。所以我們需要有一個(gè)地方可以保存這些消息,這時(shí)我們可以定義輸入和輸出消息緩沖區(qū)的類,當(dāng)我們發(fā)送或者接收消息時(shí),先把消息放到相應(yīng)的消息緩沖區(qū)里,然后再進(jìn)行相應(yīng)的處理。而這個(gè)緩沖區(qū)最好是環(huán)形的,當(dāng)緩沖區(qū)不夠用的時(shí)候能夠自己增加緩沖區(qū)大小,當(dāng)然需要有個(gè)上限。
?
當(dāng)我們有了消息緩沖區(qū)后,這時(shí)我們需要通過(guò)一種方式,把消息放入緩沖區(qū)和從緩
沖區(qū)中把消息讀取出來(lái),在放入和取出的時(shí)候可能還需要伴隨著加密與解密操作。由于在游戲中,一樣連接通常都代表著一個(gè)玩家。
???????? 我們可以定義個(gè)CPlayer類:
???????? class CPlayer
{
public:
???????? ProcessInput();???????? //讀取網(wǎng)絡(luò)上的消息并放在輸入消息緩沖區(qū)
???????? ProcessOutput();???? //把輸出消息緩沖區(qū)中的消息發(fā)送出去
???????? ProcessMsg();????????? //處理收到的消息,把相應(yīng)的消息交給相應(yīng)的處理函數(shù)
private:
???????? 輸入緩沖區(qū)
???????? 輸出緩沖區(qū)
}
?
到這里時(shí),上面的內(nèi)容通常都可以作為服務(wù)端和客戶端通用的代碼。
?
下面我們重點(diǎn)了解一下,服務(wù)端是怎么樣接著處理收到的消息的,在我接觸過(guò)的服務(wù)端中,有兩種不同的框架,不過(guò)處理方式大同小異,順便提下。
?
第一種,就像我在游戲服務(wù)端邏輯模塊處理框架中說(shuō)的差不多,在種情況之下,服務(wù)端的邏輯模塊會(huì)劃分成很多的DLL模塊,比如:
?
戰(zhàn)斗系統(tǒng)就是一個(gè)BattleSys.dll
技能系統(tǒng)就是一個(gè)MagicMgr.dll
角色系統(tǒng)就是一個(gè)RoleMgr.dll
?
然后我們有一個(gè)消息中心,當(dāng)網(wǎng)絡(luò)模塊收到消息之后把消息發(fā)送給消息中心,消息中心再把消息Buffer發(fā)送給感興趣的DLL模塊,然后這些DLL模塊用消息Buffer生成相應(yīng)的CMsg(每個(gè)消息都有消息頭,根據(jù)消息頭的消息編號(hào)可以識(shí)別相應(yīng)的CMsg),并執(zhí)行CMsg的ProcessMsg消息處理函數(shù)。
?
第二種,沒(méi)有把邏輯模塊劃分成很多個(gè)DLL,游戲邏輯都在Server中進(jìn)行處理。收到網(wǎng)絡(luò)消息之后,直接通過(guò)管理器類CpacketFactoryMgr創(chuàng)建出CMsg類(查找相應(yīng)的消息創(chuàng)建工廠,并用它創(chuàng)建出CMsg類),并執(zhí)行CMsg的ProcessMsg消息處理函數(shù)。
?
其實(shí)就是這樣的過(guò)程,注冊(cè)XXX到管理器 => 通過(guò)XXX的ID到管理器中找到XXX => XXX.DoSomething()
?
先說(shuō)到這里了…繼續(xù)學(xué)習(xí)之后再繼續(xù)……
總結(jié)
以上是生活随笔為你收集整理的网络游戏中网络模块浅析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深入探讨傅立叶变换、拉普拉斯变换、Z变换
- 下一篇: FIR数字滤波器设计_窗函数法