分类: IT业界
2012-02-15 18:34:35
基于上面的(1)(2)两篇同步方案知识,可以写个demo来试验同步的效果。
需要找一个p2p库来做系列同步算法的demo。选了RakNet-4.0.Beta5。
官方网站是
RakNet提供了如下基于UDP的信道功能:
> 丢包重发
> 高效包排序
> 包数据安全性保证,自动发现并报告被修改的包
> 流控制和包合并
> ....
在频繁发送大量大体积数据包的情况下,可能选择RakNet并不高效;
但对于选用RakNet制作游戏而言,你总可以优化发送频率和体积。
RakNet的SDK文档和Demo丰富,接口友好,跨平台,自用免费,商用收费(贵)。
要实现同一副本游戏中各peer间互联,可以用RakNet提供的几种方法:
* 所有Peer在同一局域网内,可进行预定义指令广播来发现peer,
接到指令的peer来请求连接对方。
* 针对互联网上的普遍情况互联,则要建立几种服务器来实现NAT穿透:
> Directory Server
提供每个副本游戏独立的peers信息表(由其中各peer自己先行提交),
信息表中包含各peer的ip:port,guid等信息,而每个peer在网络帧中对
Directory Server的新peer信息进行处理并向NATPunchthroughServer发起
穿透NAT的请求。
Directory Server在RakNet中有几种形式的实现:
(1)SQLite plugin
(2)lobby server
(3)PHP Directory Server
可以随便选一种,但写demo简单起见,用PHP Directory Server。
更方便的是有一个官方的PHP Directory Server可以直接用:)
> NAT类型检测Server
写Demo暂时不建立这个服务。大多数NAT还是可穿透的。
> NATPunchthroughServer
提供NAT穿透服务。即所说的UDP打洞(Punching)技术。
打洞的大致原理网络上有很多很好的文章可以查阅。
因为对port的映射方式和持续方式不同,并不是所有的NAT类型都可以穿透。
具体的NAT类型和是否可以穿透的关系如下表:
据一些调查报告称国内存在约5%的NAT不可穿透。
但一些P2P VOD的实践者称不可穿透的NAT比例在15%左右。
所以当peer间无法进行NAT穿透时,UDPProxyCoordinator + UDPProxyServer
便是终极方案,虽然成本增加,但forwarding总不会有事。
> UDPProxyCoordinator
UDPProxyServer管理器。一个UDPProxyCoordinator可接多个UDPProxyServer,
它负责指派UDPProxyServer的信息给peer进行UDP转发,
也监控各UDPProxyServer的负载情况做负载均衡,
UDPProxyServer可以动态挂接添加到UDPProxyCoordinator上。
挂接UDPProxyCoordinator时需要输入UDPProxyCoordinator的挂接密码认证。
> UDPProxyServer
负责UDP包转发。开发者可以按负载需求增添UDPProxyServer的数量。
---------------------------------------------------------------------
以上的互联结构在我的搭建方案中大致如下图:
---------------------------------------------------------------------
RakNet也提供了一个官方的NATPunchthroughServer给开发者免费使用,
但在我的实验环境中,连接状况不知为何总是很差,常连接失败。
还好RakNet的Source中自带一个项目叫 NATCompleteServer 直接包含了上面4种
服务器的实现。在Windows下用VC2005直接build即可。
而linux下build RakNet NATCompleteServer没文档说明,
Google一下,我的步骤如下:
> cd ~/sandbox/raknet
> 下载RakNet-4.0.Beta5.zip到当前目录
> unzip RakNet-4.0.Beta5.zip
> cd Source
> g++ -c *.cpp
> g++ -fPIC -shared -o libraknet.so *.o
> ar rc libraknet.a *.o
> cp libraknet.so libraknet.a /usr/local/lib
> ldconfig
> cd ../Samples/NATCompleteServer
> g++ -I/home/akara/sandbox/raknet/Source -lraknet -lpthread -lrt main.cpp -o main
> ./main
> 配置以下4种服务:
NatTypeDetectionServer
NatPunchthroughServer
UDPProxyCoordinator
UDPProxyServer
> 视需要添加UDPProxyServer进程
> DONE
默认的main程序中需要命令行互动且不能运行在后台,
但可借助screen命令解决后台运行问题。
---------------------------------------------------------------------
RakNet的Source中除了p2p的底层功能外,还提供了一些实用的插件模块。
比如很有特色的 ReplicaManager3 插件:p2p网络体系中的副本属性自动同步管理,
几乎支持任何时刻加入p2p网络的实体的各种时机的属性同步。RakNet的IrrlichtDemo
就利用了这插件来实现一个简单p2p第一人称射击游戏,入门的极佳教程。
RakNet还提供一个 RPC3 插件:C/C++远程过程调用。
---------------------------------------------------------------------
RakNet的各种插件模块的实现很有参考价值,但如果不能用脚本操纵网络接口,
那将是非常不便,所以我将上面的连接4种服务,peer互联,底层接收和发送接口
包装成客户端引擎直接可用的Python扩展模块:p2p.dll,提供如下模块接口:
p2p.init() # 初始化环境
p2p.start(max_players, port, natptserver_ip, natptserver_port) # 配置和启动
packet_handle = p2p.recv() # 收包
p2p.send(guid, data, mode, ...) # 发二进制字符串数据
event = p2p.get_packet_event(packet_handle) # 取出包的事件码
guid = p2p.get_packet_guid(packet_handle) # 取出包的来源guid
data = p2p.get_packet_data(packet_handle) # 取出二进制字符串数据
p2p.default_process(packet_handle) # 默认包处理接口
p2p.update() # 处理Directory Server和必要的事件
p2p.destroy_packet(packet_handle) # 销毁包内存
...
...
p2p.destroy() # 销毁环境
以及若干模块级常量导出。
使用p2p.dll,便可以让游戏支持p2p结构的网络了。