2D网络游戏开发(网络篇)(四)
作者:akinggw
在上一篇中,我们只是讲解了如何建立一个服务器或客户端。这一篇中,我们将讲解客户端如何和服务器进行连接。
#include "stdio.h" // Printf and gets
#include "string.h" // strcpy
#include "RakClientInterface.h"
#include "RakNetworkFactory.h"
#include "RakServerInterface.h"
#include "PacketEnumerations.h"
这是我们程序中包括的头文件,其中最主要的就是多了一个PacketEnumerations.h。这个头文件是干什么的呢?
打开它的文件可以看到就是一些宏变量,用于处理网络引擎在运行过程中得到的信息。我在这里就不一一进行翻译,在以后的应用中,我们将进行详细得讲解。
首先,在变量的声明中,多了一个包的声明:
Packet *packet;
Packet是网络传输中用于存储数据的一个数据结构,它的结构如下:
Struct Packet
{
PlayerID playerId;
Unsigned long length;
Unsigned long bitsize;
Char *data;
}
PlayerID表明了包的出处。每一个连接服务器的客户端都将被分配一个唯一的ID号,用于标识自己。
Length和bitsize告诉你这个结构中的数据长度和比特大小。
*data 就是这个包中的数据。
然后,我们就建立客户端或服务器,代码和前面的一样。
客户端或服务器建立好以后,我们就判断建立的是客户端还是服务器:
if (rakServerInterface)
{
// 服务器运行在端口60000处
rakServerInterface->Start(32, 0, 0, 60000);
}
else
{
// 运行客户端
printf("输入服务器IP地址:n");
gets(str);
// 127.0.0.1 designates the feedback loop so we can test on one computer
if (str[0]==0)
strcpy(str, "127.0.0.1");
rakClientInterface->Connect(str, 60000, 0, 0, 0);
}
在rakServerInterface->Start(32, 0, 0, 60000);这个语句中,第一个参数表明你的服务器允许同时连接多少个客户端,在这里,我们设置的是32。就表示同时可连接32个客户端。这个参数最大可以设置成65535;第二个参数做保留之用,设置成0;第三个参数用于设置多久进行服务器更新,参数要大于等于0,表示用每隔当前设置的毫秒数进行更新,这里设置的是0;最后一个参数用于设置服务器的端口 (值得注意的是,客户端的端口应和服务器的端口一样),另外,设置的端口号应该在32000之上,因为,在32000之下的端口都被保留了,用于其它,诸如WWW,FTP,POP3等服务了。
我们接下来看一下rakClientInterface->Connect(str, 60000, 0, 0, 0),这个方法用于客户端连接服务器。第一个参数表示你要连接的服务器的IP地址,如果是在自己这台计算机调试程序,直接输入”127.0.0.1”或“localhost”;第二个参数表示要连接的服务器的端口;第三个参数表示要连接的客户端端口,主要就是用于客户端之间交换数据;第四个参数不要;第五个参数和服务器start函数中的第三个参数一样.
然后,我们就在循环中处理数据:
while (1)
{
if (rakServerInterface)
packet=rakServerInterface->Receive();
else
packet=rakClientInterface->Receive();
if (packet)
{
switch (packet->data[0])
{
case ID_REMOTE_DISCONNECTION_NOTIFICATION:
printf("另一个连接已经断开.n");
break;
case ID_REMOTE_CONNECTION_LOST:
printf("一个客户端丢失连接.n");
break;
case ID_REMOTE_NEW_INCOMING_CONNECTION:
printf("一个客户端已上线.n");
break;
case ID_CONNECTION_REQUEST_ACCEPTED:
printf("我们的连接要求已经接受.n");
break;
case ID_NEW_INCOMING_CONNECTION:
printf("有新连接.n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
printf("服务器已满.n");
break;
case ID_DISCONNECTION_NOTIFICATION:
if (rakServerInterface)
printf("客户端丢失.n");
else
printf("连接中断.n");
break;
case ID_CONNECTION_LOST:
if (rakServerInterface)
printf("客户端丢失连接.n");
else
printf("连接丢失.n");
break;
default:
printf("ID信息 %i 已经到达.n", packet->data[0]);
break;
}
if (rakServerInterface)
rakServerInterface->DeallocatePacket(packet);
else
rakClientInterface->DeallocatePacket(packet);
}
}
下面,我们详细地讲解它们的作用。
if (rakServerInterface)
packet=rakServerInterface->Receive();
else
packet=rakClientInterface->Receive();
从服务器或客户端接受数据,将它保存在packet中。
接下来进行处理。
因为网络引擎在运行过程中要返回一些信息,这些信息有的是给客户端的,有的是给服务器的,而有的是两个都给的。
Packet中返回的第一个data[0]表明了这些类型,这些类型的解释在PacketEnumerations.h中。
由于篇幅的关系,我在这里就不一一进行解释,大家还是自己去看吧。
if (rakServerInterface)
rakServerInterface->DeallocatePacket(packet);
else
rakClientInterface->DeallocatePacket(packet);
是指接收处理好了的包,让它生效。
最后,和前面一篇文章一样,释放掉我们所占有的内存。
if (rakClientInterface)
RakNetworkFactory::DestroyRakClientInterface(rakClientInterface);
else if (rakServerInterface)
RakNetworkFactory::DestroyRakServerInterface(rakServerInterface);
return 0;
}
服务器截图:
图注1 |
客户端截图:
图注2 |
关于更多内容请访问金桥科普网站(http://popul.jqcq.com)游戏开发栏目,如你需要游戏开发方面的书籍请参考金桥书城游戏频道(http://book.jqcq.com/category/1_70_740.html)。如果你在阅读本篇文章时有什么好的建议请来信给我,我的E_mail: akinggw@126.com. 如果你在使用SDL时有什么问题,请到金桥科普网站(http://popul.jqcq.com)游戏开发栏目,我将详细地为你解答。