现行开发的软件中,基本没有啥是不联网的。连一个小小的游戏,也要联网,去下载点广告什么的。那么网络层的是不是可以有很多东西可以重用的呢?
本人之前在一个游戏公司做服务器端开发。有一个网络架构是这样设计的。
网络使用了IO复用模型select。当然,对于现在的服务器,可以使用epoll代替。
一个Opcodes类,类成员都是静态的常量,用于表示与服务器通信的操作码。我们称它们为协议号。对于每一个操作,都会有一个协议号对应。比如客户端登录,客户端发给服务器进验证,使用一个CSLOGIN的常量表示。服务器验证后,将结果返回,可以使用一个SCLOGIN的常量表示。等等。
一个Optable类。这个类使用一std::map来记录每一个协议号的操作。map中的first value是协议号,second value是对应协议的处理逻辑回调函数。这个类应该设计成单例的。在main函数中,进行网络通信之前应该将这个单例中的map设计好,即将所有的协议号和回调函数insert到map中。这里还有一点要求,就是回调函数的声明必须是一样 ,不然map就定义不了。所以,回调函数可以设计成void (*)(unsigned
char*)这样结构。因为收到的消息也是字节流。先从流中解析出包的长度,再解析出该长度的消息。当然,为了方便处理,还可以封装多一层函数,这个函数的功能是这样的:我们定义协议的时候,会要求将什么参数传到网络中去,比如将用户名和密码发给服务器,那么就会参数就会是这样string name, string password。这样就可以在回调函数中调用相应的这个函数,而这个函数应该由子类去重写其对应的业务逻辑。那这些业务逻辑应该放在哪里呢?下面讨论。
设计一个Receiver类,让要进行接收消息的端去继承这个类。比如,服务器可以有一个用于监听连接的类,然后这个类的函数监听到一个连接,然后将这个连接new一个新的对象,而这个对象所对应的类应该继承Receiver类,这样就可以去重写上面所说的方法了。
整理一下逻辑(以服务器为例):
- 服务器收到包,发给对应的处理对象。
- 解析出协议号。
- 在optable中根据协议号找出处理函数。
- 处理函数调用重写的业务逻辑函数进行处理。
也就是说,这个网络层是有东西可以封装的。如果封闭了服务器(客户端),optable, receiver等类,那么,以后要用这个网络层,只要在opcodes中加入协议号。子类化receiver类,就能进行处理这些逻辑。
以上是网络层的设计思想。也可以看成是一个概要设计,接下来我会对这个设计进行实现。实现完成后,将会加入我的git中。
当然,在实际使用中,已经有了很多网络架构,如ICE,ACE等,可以使用这些架构使项目的速度快很多。但是,自己封装的网络层可以进行自己定制,实现更高效的网络架构。见仁见智吧。