forwarder概况

Tags:

5个月没更新博客,是因为这段时间主要用在开发forwarder。forwarder是因为工作需要而开发的一个工具,它统一了游戏前后端之间、后端各个服务之间的通信,目前forwarder不仅已经通过了初步的压力和稳定性测试,并且已经在项目中发挥了实际作用。

目前成果

  1. 已经实现两种通信模式:enet(udp)和websocket(http based tcp)的一键切换

我们一开始用了websocket来实现服务端和客户端之间的通信。服务端架构做深入后,涌现了复杂的多服务器间通信的需求,为求快速开发,我们用上了npm上的一个websocket库,这样前后端、后端之间的通信模式就统一了:js + websocket。但是这个websocket库偶而会出现一个莫名其妙的error,第三方库的原因,修复无望,也不想死磕这个websocket,于是发现了新的方案:enet。

enet是一个神奇的库,它把udp通信做了一层封装,使得通过enet通信,不仅可以发不可靠的udp,也可以发可靠的udp,使得通过udp也可以做网游(作者似乎也是某个游戏公司的)。

更重要的是,tcp相比udp,有一个缺点,在网络状况不好时,tcp表现得很差,原因是RTO(Retransmission TimeOut)重传定时器跟不上RTT(Round Trip Time)的变化(这也是tcp的故意设计)。具体细节推荐这篇文章:TCP超时重传机制探索。RTO过高时,延迟就会变大,对有实时联网战斗的游戏是致命的。

除了可靠性,enet还有很多features:有序、连接管理、带宽控制、跨平台等,都是无缝地从tcp通信切换到enet通信的有利条件。

但我们项目如果要切换到enet还有很多问题,例如:

  • 我们的web版客户端无法嵌入enet库(因为浏览器不支持),即使服务端支持了enet,web客户端也无法与之建立通信
  • websocket在浏览器的js、spidermonkey的js、node.js(npm有现成的库),都算是内置的功能,但enet就需要我们自行解决这些平台问题了

因此,forwarder就应运而生了。forwarder对通信方式做了一层简单的抽象,把enet亦或者websocket都隐藏了,使得通过forwarder做通信时,不需要太关心通信方式细节。

对于上面第一个问题就有了解决方案,服务端只需要开放2个访问端口,一个tcp(websocket)、一个udp(enet),前者给web客户端连接,后者给支持enet的客户端连接,例如手机端、PC端。forwarder收到websocket线路来的包时,也交给enet线路的packer_handler处理就可以了,发包接口也类似。

第二个问题的处理就是写driver,forwarder对收发的packet包一层scheme,用于做加密等功能,而web端既然无法使用forwarder的代码,那么就只能写一个scheme parser和一套简易的forwarder-js接口,实现解包、压包;node.js的话也实现了一个forwarder-node了;而spidermonkey或者说cocos2d-x中的spidermonkey,我也写了一套driver用于项目中。

还有一个driver是web-js。因为浏览器不支持native代码,所以我实现了一个纯js版本的forwarder协议解析器,并封装了和其他driver一样的forwarder接口。但这个解析器暂时不支持上述的加密、压缩等功能。要实现这些功能需要接入web版的AES加密插件等,暂时还不必要。

  1. 动态长度header,支持加密、压缩、base64、ip查询

加密使用了AES算法,密钥要求128位;压缩使用了zlib库;动态长度header是指,在不开启任何功能时,单个packet的header最少需要8个字节,根据开启的flag,header会动态增长。(初期写了固定长度的header,发现很不好使,中间重构了一遍)

总的来说,forwarder还是一个临时做的小东西,没什么技术含量,只是应付目前的工作需要。

(未经授权禁止转载)
Written on March 18, 2017

写作不易,您的支持是我写作的动力!