网络游戏实时动作同步方案手记(3)

来源:互联网 发布:考勤机如何导出数据 编辑:程序博客网 时间:2024/06/06 16:40

by AKara 2010-09-14 @ http://blog.csdn.net/akara @ akaras(at)163.com

---------------------------------------------------------------------

  基于上面的(1)(2)两篇同步方案知识,可以写个demo来试验同步的效果。

  需要找一个p2p库来做系列同步算法的demo。选了RakNet-4.0.Beta5。
  官方网站是http://www.jenkinssoftware.com/
  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的数量。

---------------------------------------------------------------------

  以上的互联结构在我的搭建方案中大致如下图:

p2p 

---------------------------------------------------------------------
  
  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结构的网络了。

---------------------------------------------------------------------