RakNet--Connecting
连接到其他的系统 |
寻找连接目标
有5个方式来发现要连接到的系统: 1. 直接输入IP地址(这个广为人知)。 2. LAN广播 3. 使用ClientServer/CloudClient插件 4. 使用游戏大厅服务器或房间插件 5. 使用目录服务器DirectoryServer 选择1:输入IP地址 从编码的角度看,最简单,最容易的方式就是将IP地址或域名硬编码,或使用GUI询问用户,让他们来输入他们想要连接的系统的IP地址。很多例子使用这种方法。游戏刚刚出来的时候支持这种方式,这种方式是唯一可用的方式。 优势: 1. 对于编程人员和美工的要求较少,GUI可以很简单。 2. 如果IP地址或域名是固定的,例如运行的是一个专用服务器,这个就是最好的解决方案。 不足: 1. 缺乏灵活性 2. 用户仅仅可以与他们知道的人们玩游戏。 注意:要连接到本机上的RakPeer实例或其他相同的应用程序,IP地址要使用127.0.0.1或localhost。
选择2:LAN广播 RakNet支持在局域网中广播一个数据报发现其他的系统的功能,使用可选的数据来发送和检索相似的应用程序。例子LANServerDiscovery说明了这项技术。 在RakPeerInterface中,Ping函数可以做到这些,如下所述: rakPeer->Ping("255.255.255.255", REMOTE_GAME_PORT, onlyReplyOnAcceptingConnections); REMOTE_GAME_PORT应该是其他系统上你关心的应用程序运行的端口。onlyReplyOnAcceptConnections是一个布尔值,来标识其他系统是否需要回复,即使你没有可用连接连接到该系统。 开放系统会回复ID_UNCONNECTED_PONG,例如下面的例子: if (p->data[0]==ID_UNCONNECTED_PONG) { RakNet::TimeMS time; RakNet::BitStream bsIn(packet->data,packet->length,false); bsIn.IgnoreBytes(1); bsIn.Read(time); printf("Got pong from %s with time %i\n", p->systemAddress.ToString(), RakNet::GetTime() - time); }
为了发送用户数据,调用RakPeer::SetOfflinePingResponse(customUserData, lengthInBytes);,RakNet会拷贝传递给它的数据,然后将数据返回回来追加到ID_UNCONNECTED_PONG。 注意:在RakPeer.cpp中有一个硬编码的MAX_OFFLINE_DATA_LENGTH限制了用户的数据长度。如果数据比这个值大,修改这个值,重新进行编译。
优点: 1. 在系统启动后,可以自动加入游戏,不需要GUI或用户交互。 2. 在LAN上最好的寻找游戏的方法。 不足: 1. 在一般的因特网上不可用 2. 不如lightweight database插件灵活
选项3:使用CloudServer/CloudClient插件 不用修改,CloudServer/CloudClient插件直接就可以作为目录服务器。 选项4:使用游戏大厅服务器或房间插件 游戏大厅服务器提供了一个数据库驱动服务器,用于交互和开始游戏。它提供了一些功能,例如好友,配对,邮件,排名,即时通信,快速配对,房间,或房间协调。 参考Lobby2Server_PGSQL和Lobby2Client中对这项功能的使用方法。 优势: 1. 玩家加入游戏最灵活的处理方式 2. 允许用户在开始游戏之前进行交互 3. 建立社区 4. 支持多个标题 不足 1. 需要一个分离的专用服务器来承载这个插件,服务器需要有数据库支持。 2. 功能相对于简单的游戏列表较大,且复杂,需要时间和编程方面投入更多。
选择5: DirectoryServer.php DirectoryServer.php和相关的代码可以在Samples\PHPDirectoryServer2中找到。这种方式是给出游戏列表比较廉价的方式,游戏上线后使用web服务器来存储,游戏信息是使用字符串来给出。获得更多信息,参考这个功能的参考手册。 优点: 1. 不需要专用的服务器,仅需要一个web页 缺点: 1. 不灵活 2. 有时不可用(需要多次访问)
发起连接尝试 一旦知道了想要连接的远端系统的IP地址,使用RakPeerInterface::Connect()方法初始化一个异步的连接尝试,连接参数如下: ConnectionAttemptResult Connect( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey=0, unsigned connectionSocketIndex=0, unsigned sendConnectionAttemptCount=6, unsigned timeBetweenSendConnectionAttemptsMS=1000, RakNet::TimeMS timeoutTime=0 )
1. host是一个IP地址,或域名 2. remotePort是远端系统监听的端口,传递给Startup()函数的端口参数。 3. passwordData是随着连接请求发送的二进制数据。如果这个参数与传递给RakPeerInterface::SetPassword()的参数不同,远端系统会回复ID_INVALID_PASSWORD。 4. passwordDataLength是passwordData的长度,单位是字节。 5. publicKey 是远端系统上传递给InitializeSecurity()函数的公用密钥参数。如果你不适用,传递0。 6. connectionSocketINdex是你要发送的客户端的Socket在传递给RakPeer::Startup()函数的socket描述符的数组中的索引。 7. sendConnectionAttemptCount是在确定无法连接前要做出的发送尝试次数。这个也用于MTU检测,使用3个不同的MTU大小。默认的值12意味着发送每个MTU四次,这对于容忍任何原因的包丢失也是足够的了。更低的值意味着ID_CONNECTION_ATTEMPT_FAILED会更快返回。 8. timeBetweenSendConnectionAttemptsMS是进行另外一次连接尝试要等待的毫秒数。比较好的值是4倍的ping值。 9. 如果消息不能发送,在丢掉远端系统之前,为这次连接,timeoutTime指出了要等待多少毫秒。默认值是0,意味着使用SetTimeoutTime()方法中的全局值。
连接尝试成功Connect()会返回CONNECTION_ATTEMPT_STARTED值,如果失败会返回其他的值。 注意:Connect()返回TRUE并不意味着已经连接成功。如果连接成功,应该会返回ID_CONNECTION_REQUEST_ACCEPTED。否则,会收到一条错误消息。 连接消息作为Packet::data结构的第一个字节返回
连接关闭: ID_DISCONNECTION_NOTIFICATION, ID_CONNECTION_LOST
解决ID_CONNECTION_ATTEMPT_FAILED错误 ID_CONNECTION_ATTEMPT_FAILED是一条概述性消息,意味着与远端系统没有建立连接。可能的原因包括如下几方面: 1. IP地址错误 2. 远端系统没有运行RAkNet,或RakPeerInterface::Startup()在这个系统上没有调用。 3. 远端系统启动了RakNet,但是RakPeerInterface::SetMaximumIncomingConnection没有调用。 4. 防火墙阻止了你选择的端口上的UDP数据包。 5. 远端系统的一个路由器阻塞了进入你选择的端口上的UDP数据包。参考NAT Punchthrough插件解决这个问题。 6. 在Windows Vista上,网络驱动安全服务器包有事破坏了UDP,不仅仅是RakNet,甚至是DirectPlay。这个服务包应该关闭或者不要安装。 7. Secure Connections启用了,但是安全检查不正确。 8. 你的iP地址被RakPeerInterface::AddToBanList()函数禁止了。注意有些插件例如Connection filter,有可选的自动禁止IP地址的功能。
假设你已经能够连接上了,转向下一部分: Creating Packets |
请参阅 |
Index Connection Filter Creating Packets Lightweight Database plugin NAT Punchthrough plugin Secure connections FAQ |