原文:http://blog.csdn.net/deletex/archive/2010/03/10/5365545.aspx
在网络游戏中,不论是服务端还是客户端都需要网络通讯的功能模块,而一个优秀的成熟的网络通讯模块,又可以用于多个游戏产品中。
于是,在学习的过程中,设计和实现一个可复用的网络通讯模块,变得非常的有意义。
通过思考我们可以一步一步的来实现这样的模块:
我们应该知道对原生的 Socket API 进行封装是有必要的,也许当前服务端是运行在 window 环境下,也许改天就有可能要在 Linux 下面运行。而对原生 Socket API 进行封装,可以很方便的让我们进行两者的切换,并且不需要我们付出多大的代价。
可以像下面这样封装 , 放在 SOCKET_API 命名空间下面 , 其他 API 类似:
UINT SOCKET_API:: recv_ex ( SOCKET s , void * buf , UINT len , UINT flags )
{
#if defined __LINUX__
… .
#elif defined __WINDOWS__
… .
#endif
}
我们都知道游戏通常都是使用 TCP 来实现通讯的 , 而 TCP 需要下面这些最基本的功能及对 SOCKET 进行设置或者获取信息的函数。
server
client
bind
listen
accept
send
recv
close
connect
send
recv
close
我们希望把这些功能都封闭到一个 CSocket 类中。
class CSocket
{
public :
构造函数, 析构函数, 初始化函数 ……
BOOL connect (const CHAR * host , UINT port ) ;
UINT send (const VOID * buf , UINT len , UINT flags = 0) ;
SOCKET accept ( struct sockaddr * addr , UINT * addrlen ) ;
其他函数, 例如receive ,bind,listen,close,get 和set 变量接口,有效性判断等等 ……
public :
SOCKET m_SocketID ;
SOCKADDR_IN m_SockAddr ;
CHAR m_Host [IP_SIZE ];
UINT m_Port ;
};
不论是服务端还是客户端都没有办法做到一收到消息就马上响应请求,然后直接把
这个消息丢弃掉。所以我们需要有一个地方可以保存这些消息,这时我们可以定义输入和输出消息缓冲区的类,当我们发送或者接收消息时,先把消息放到相应的消息缓冲区里,然后再进行相应的处理。而这个缓冲区最好是环形的,当缓冲区不够用的时候能够自己增加缓冲区大小,当然需要有个上限。
当我们有了消息缓冲区后,这时我们需要通过一种方式,把消息放入缓冲区和从缓
冲区中把消息读取出来,在放入和取出的时候可能还需要伴随着加密与解密操作。由于在游戏中,一样连接通常都代表着一个玩家。
我们可以定义个 CPlayer 类 :
class CPlayer
{
public :
ProcessInput(); // 读取网络上的消息并放在输入消息缓冲区
ProcessOutput(); // 把输出消息缓冲区中的消息发送出去
ProcessMsg(); // 处理收到的消息 , 把相应的消息交给相应的处理函数
private :
输入缓冲区
输出缓冲区
};
到这里时,上面的内容通常都可以作为服务端和客户端通用的代码。
下面我们重点了解一下,服务端是怎么样接着处理收到的消息的,在我接触过的服务端中,有两种不同的框架,不过处理方式大同小异,顺便提下。
第一种,就像我在 游戏服务端逻辑模块处理框架 中说的差不多,在种情况之下,服务端的逻辑模块会划分成很多的 DLL 模块,比如:
战斗系统就是一个 BattleSys.dll
技能系统就是一个 MagicMgr.dll
角色系统就是一个 RoleMgr.dll
然后我们有一个消息中心 , 当网络模块收到消息之后把消息发送给消息中心,消息中心再把消息 Buffer 发送给感兴趣的 DLL 模块,然后这些 DLL 模块用消息 Buffer 生成相应的 CMsg (每个消息都有消息头,根据消息头的消息编号可以识别相应的 CMsg ) , 并执行 CMsg 的 ProcessMsg 消息处理函数。
第二种,没有把逻辑模块划分成很多个 DLL ,游戏逻辑都在 Server 中进行处理。收到网络消息之后,直接通过管理器类 CpacketFactoryMgr 创建出 CMsg 类(查找相应的消息创建工厂 , 并用它创建出 CMsg 类),并执行 CMsg 的 ProcessMsg 消息处理函数。
其实就是这样的过程,注册 XXX 到管理器 =gt; 通过 XXX 的 ID 到管理器中找到 XXX =gt; XXX.DoSomething()
先写到这里了 … 继续学习之后再继续 ……
锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛
- 还没有人评论,欢迎说说您的想法!