RakNet是一款面向游戏基于UDP的高性能网络库,注意它开源但并非完全免费。
有一些商业化介绍,通过导航可以找到入门指导(RakNet Manual)、Doxygen文档、论坛
它的好处在于作者会不定时来扫贴免费答疑解惑,当然你必须用英语,还必须让他看懂。有一段时间我是发现他每天定时会来一次。现在去看好像没那么频繁了。RakNet的免费授权中是说了论坛支持的,更多的支持就要付费授权。你的使用上了一定规模也要付费授权。
正常的下载需要填写个邮箱,然后下载地址邮给你。有了上面的链接,你就可以直接下载。
RakNet开始的第一步,也是为数不过的几步,创建RakPeerInterface:
RakPeerInterface* rakpeer = RakPeerInterface::GetInstance();
设置绑定的地址到SocketDescriptor
SocketDescriptor sd;
strcpy(sd.hostAddress,address); //一定是ip地址,空字符串等同INADDR_ANY
sd.port = port;
启动,设置最大连接数和绑定地址数.可以多地址多端口哦.
mRakPeer->Startup(maxmumConnections,&sd,addressCount); //其中addressCount是1
下面是连接,连接支持域名,ip,不过域名会使用gethostbyname有可能阻塞.
connRet = mRakPeer->Connect(target,port,CONN_PASSWORD,CONN_PASSWORDLENGTH);
连接是异步的,那么连接结果以及被连接方是如何工作的呢?使用Receive
packet = mRakPeerHelper->Receive();
需要由线程或者主线程不断去调用这个这个函数拾取网络包.packet是RakNet定义的结构,里面有消息的地址,guid,长度等.在data中则包含了此次的数据主体. 数据主体的第一个字节是此次数据的类型,预定义的类型都是通知和反馈型,数据包类型有待开发者自己确定.
switch(packet->data[0]) //注意,没有写break,值只是其中一小部分
{
case ID_USER_PACKET_SPECIFIC: //用户定义
case ID_ADVERTISE_SYSTEM: //局域广播
case ID_CONNECTION_LOST: //连接丢失
case ID_ALREADY_CONNECTED: //目标已经连接
case ID_CONNECTION_REQUEST_ACCEPTED: //连接成功,这是发起方
case ID_NEW_INCOMING_CONNECTION: //新的进来了,这是被动方
case ID_CONNECTION_ATTEMPT_FAILED: //连接尝试失败,即连接失败
case ID_INVALID_PASSWORD: //连接失败,密码不匹配
case ID_INCOMPATIBLE_PROTOCOL_VERSION: //连接失败,RakNet版本不兼容
}
如果连接成功,连接方得到ID_CONNECTION_REQUEST_ACCEPTED,被连接方得到ID_NEW_INCOMING_CONNECTION,他们就可以互通数据了. 数据的定义要确保预留首字节作为类型.由于RakNet已经使用了一部分,开发者的数据类型需要大于ID_USER_PACKET_ENUM
发送函数除了指定包和长度,还指定了包优先级,包可靠类型,包通道,目标id,是否全发标志.
mRakPeer->Send((char*)packet,DataLenInPack,(PacketPriority)priority,(PacketReliability)packStyle,orderingChannel,guid,boardcast))
收包和前面处理连接反馈一样, switch(packet->data[0])来筛选数据类型,得到数据内容.
连接双方都可以随时断开连接
mRakPeer->CloseConnection(pi->guid,true,orderingChannel,LOW_PRIORITY);
断开本质上是发送了断开消息给对方,根据需求可能需要考虑紧迫性问题,以及通道问题,所以关闭函数提供了这样的参数.如果关闭信息顺利到达对方处,对方会得到ID_DISCONNECTION_NOTIFICATION通知,否则的话,对方会在超时到来时得到通知ID_CONNECTION_LOST.
销毁RakPeerInterface:
RakPeerInterface::DestroyInstance(iface);
实际使用RakNet过程中,遇到了一些小不方便的地方,还有一些进阶使用,在我的XNetEngine封装中有所体现.具体的请转到XNetEngine—对RakNet的封装和使用.
在基本网络框架的基础上,RakNet做了很多的插件,他们以一个链的形式,优先处理和过滤收到的信息,以实现扩展的内容.例如Fully Connected Mesh 2实现所有节点的两两互连;NAT punchthrough实现内网的打孔直连等等,你可以在RakNet Manual中一一查看.
RakNet是一个跨平台库,虽然只是个网络引擎,但是他里面有很完整的数据结构类,例如list,map,queue,hash等等,有一次精心研究了一下他的DS_MemoryPool发现算法非常精妙. 除了这些,你还能从里面学到一些插件的架构和实现方法,单例声明,HTTP连接,Email发送,压缩,流IO等等等等,所有这些都是跨平台的.足够啃老半天的.
RakNet还做了一些功能拓展(位于源码目录/DependentExtensions),实际也是引入了其他一些第三方库,它就像一个小金矿,一方面你可以直接使用它,一方面可以打开源码,自己掌握它,它扩展了你的眼界. 例如miniupnpc是一个协调路由开放端口映射的库;speedx是个小巧精悍的语音编解码库,让你开发语音对话更容易;Swig这个就牛了,通过编写一些辅助声明(RakNet作者已经搞定),它可以把RakNet代码自动转成C#代码,编出一个C#可以用的RakNet模块.实际使用过程中发现模板类的类型是需要在声明文件里指明的,如果你用了奇葩的类型给到模板类,可能作者并没有帮你声明.于是你可能需要改声明哦.想要完全搞定它,你可能还得了解一下Swig这个神奇的物体.