通信协议

在传统的互联网应用中,通信协议通常被设计成文本方式,这是一个广泛而基础的网络信息交互,互联网本身是不局限于操作系统,编程语言,PC,终端,手机等具体平台和技术。所以协议的设计应足够通用。而在网络游戏中,为了简单和方便,通信协议通常是专用的,我们通常会具体到特定语言和平台来设计协议。


回顾以前我参与的项目,在通讯协议的设计上也是一步一步的改进的,在最早期的协议设计,我们采用简单的二进制结构描述,比如,一个聊天消息可能是这样的:2字节的包长度+1字节的协议类型+2字节的协议ID+聊天者ID+聊天内容。后来感觉这种方式容易出错和不易维护,我们提取出了包头和包体,都以c struct来描述,包头信息通常包括长度,类型和ID,包体是一个特定的struct,这样,当某个特定的消息发生变化,能在一定程度上依赖编译器检查出错误,并且对某个字段的长度信息不太敏感,在修改了长度信息后,只需要重新编译一次即可。再到后来,我发现程序员经常忘记初始化消息,或者忘记给消息的某个字段赋值,我又在消息结构中定义了构造函数,并且不提供缺省构造函数,这样进一步的依赖编译器提醒程序员初始化问题。再后来,我们发现带有很多变长数据的消息难以用struct描述,又引入了序列化机制。这大概就是我们现在使用的通信协议的现状。


    时光荏苒,由于启动了新项目,前几天我又在思考这个问题,在我们以前的协议设计中,一个消息是由消息头和消息体构成的,消息头大致是这样:


所有的消息都从这个消息头派生,并通过宏自动生成一些代码来构建消息。这样,对于一个聊天消息,我们会有msg_chat_say_cg(客户端到服务器),msg_chat_say_gc(服务器到客户端)这种消息,2个消息的唯一区别是消息头的流向(msg_direct)不一样,这样,我们不得不写2个重复的消息体。圣人教导我们:Don’t Repeat Yourself,于是,把这个消息体拿出来放到一个公共的地方复用。但不管怎样,这种方式必然会导致消息头和消息体的强耦合。为了分离这种耦合,我们决定把消息的构造交给外部程序去做,即消息的定义者尽量只给出msg_type 和msg_id这种元数据以及消息体。大致实现如下:

这样,聊天消息大致是这样实现:

这种做法带来的另一个问题是消息的发送者更可能出错,比如用一个聊天消息类型发送了一个行走消息,而消息的定义只需要一次,发送通常会有很多次,针对这个问题的解决方法是仍然由消息制定者来制作消息:

对于消息发送者来说应该这样处理:

对于消息发送者来说,可能和前一种做法并没有太大的区别,但我想对于消息的制定者来说更加容易维护。

最后说一下,近年由于webgame的异军突起,很多项目都很可能有和webgame对接的需求,从而实现webgame和mmorpg互通——同一组服务器,多个表现层,由于以前网络游戏协议的私密性(通常会有加密和压缩等部分),在做协议互通的时候可能需要更加精细的协议设计。我的方案是,协议仍采用二进制流通信,真正的实现互通的方式在于序列化,只需要保持一致的序列化方法,那么异步平台自然也就能通信了。至于加密问题,在我们的设计中属于网络层的范畴,最简单的方案就只需要保持相同的加密算法即可。

最最后再说一点,协议设计仅在于网络层次之上,在复杂的游戏逻辑编写过程中,协议只是提供一种机制,游戏逻辑需要在这种机制上提供一种更高层次上的通信方式,一个合理的设计,游戏逻辑程序员应该不需要关注具体协议的实现细节,也不需要掌握更多通讯方面的知识,他只关注接口即可。基于这个想法,我们在游戏逻辑层次上更需要的是一种类似RPC的通信方式,这里就不展开谈了,我想以后会专门写一点这方面的东西。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值