RakNet网络框架简单入门

RakNet网络框架简单入门

raknet是采用c++语言编写的一套基于UDP协议的高性能网络框架,主要使用在游戏中,当然了,其他项目也可以使用。还有,他是跨平台的。

由于目前的手游项目的网络框架使用的就是它,花了点时间看了看,这里写个比较简单的例子来说明该如何使用它。要是在项目中使用,只需要扩展这个代码即可。

raknet官网上下载资料包,使用vs2008及以上的版本打开里面的项目工程,编译里面的DLL项目,生成RakNet_DLL_Debug_Win32.lib和RakNet_DLL_Debug_Win32.dll文件,当然这是Debug模式下。

现在我们实现这样一个效果,server接受client发送过来的数据,并添加一些字符串否再发给client,client显示发送和接受的数据。发送的内容使用一个结构体来存放。

我们新建一个文件夹,将刚刚生成的lib文件拷贝进去,并且将解压出来的source文件夹一起复制过去,里面含有raknet的头文件。

在vs中创建win32控制台程序工程,放到新建的文件夹中,工程属性中配置属性C/C++常规附加库包含目录中添加source文件夹,连接器输入中添加RakNet_DLL_Debug_Win32.lib,连接器常规附加库目录协商lib文件所在的目录。

首先看看server端代码:NetMgr.h

#ifndef __NETMGR_H__

#define __NETMGR_H__

class NetMgr

{

public:

NetMgr();

~NetMgr();

//初始化网络

void init_net_work() const;

//接收网络消息

void net_work_update() const;

//发送数据给client

void send_data_to_client() const;

//接收client的数据

void receive_data_from_client(const unsigned char *msg_data) const;

private:

//处理server发送过来的消息

void _process_client_message() const;

public:

unsigned short server_port;

int max_client;

};

#endif

再看看NetMgr.cpp:

#include "NetMgr.h"

#include "../../Source/RakPeerInterface.h"

#include "../../Source/RakNetTypes.h"

#include "../../Source/MessageIdentifiers.h"

#include "../../Source/BitStream.h"

#include

#include "ServerClientMessage.h"

#include "ServerClientStruct.h"

RakNet::RakPeerInterface *net_peer; //网络消息

RakNet::Packet *net_packet; //网络消息包

NetMgr::NetMgr()

: server_port(10001)

, max_client(1000)

{

}

NetMgr::~NetMgr()

{

}

//初始化网络

void NetMgr::init_net_work() const

{

//初始化网络消息

net_peer = RakNet::RakPeerInterface::GetInstance();

if (NULL == net_peer)

{

std::cout << "GetInstance failed" << std::endl;

return;

}

std::cout << "Start Game Server ......" << server_port << std::endl;

//开启网络线程来监听相应的端口

//Startup函数的第一个参数是接受的最大连接数,客户端一般设置成1

//第二个参数就是要监听的端口。SocketDescriptor监听制定的端口,他是一种套接字,服务器一般设置成SocketDescriptor(server_port, 0)

//第三个参数是SocketDescriptor数组的大小,传1表明不确定。

int start_up = net_peer->Startup(1, &RakNet::SocketDescriptor(server_port, 0), 1);

if (start_up > 0)

{

std::cout << "Startup failed" << std::endl;

return;

}

//SetMaximumIncomingConnections容许最多的连接数量

net_peer->SetMaximumIncomingConnections(max_client);

}

//接收网络消息

void NetMgr::net_work_update() const

{

//Receive从消息队列中获取消息

for (net_packet = net_peer->Receive(); net_packet; net_peer->DeallocatePacket(net_packet), net_packet = net_peer->Receive())

{

switch (net_packet->data[0])

{

case ID_REMOTE_DISCONNECTION_NOTIFICATION:

std::cout << "Another client has disconnected" << std::endl;

break;

case ID_REMOTE_CONNECTION_LOST:

std::cout << "Another client has lost the connection" << std::endl;

break;

case ID_REMOTE_NEW_INCOMING_CONNECTION:

std::cout << "Another client has connected" << std::endl;

break;

case ID_CONNECTION_REQUEST_ACCEPTED:

std::cout << "Our connection request has been accepted for server" << std::endl;

break;

case ID_NEW_INCOMING_CONNECTION:

std::cout << "A connection is incoming " << std::endl;

break;

case ID_NO_FREE_INCOMING_CONNECTIONS:

std::cout << "The server is full" << std::endl;

break;

case ID_DISCONNECTION_NOTIFICATION:

std::cout << "A client has disconnected" << std::endl;

break;

case ID_CONNECTION_LOST:

std::cout << "A client lost the connection " << std::endl;

break;

case ID_USER_PACKET_ENUM:

_process_client_message(); //用户自定义消息入口

break;

default:

std::cout << "Message with identifier %d has arrived" << net_packet->data[0] << std::endl;

break;

}

}

}

// client 发送过来的消息

void NetMgr::_process_client_message() const

{

int message_id = 0;

//将消息解析出来,使用BitStream

//IgnoreBytes忽略掉最外层的raknet的消息类型

RakNet::BitStream bs_in(net_packet->data, net_packet->length, false);

bs_in.IgnoreBytes(sizeof(RakNet::MessageID));

bs_in.Read(message_id);

//偏移掉自定义的消息,获取实际数据,raknet的消息类型大小是一个字节,自定义的结构体是4个字节(32位机器)

unsigned char *msg_data = net_packet->data;

msg_data += sizeof(unsigned long) + sizeof(unsigned char);

switch (message_id)

{

case msg_connect_server:

this->receive_data_from_client(msg_data);

break;

default:

break;

}

}

// 接收 client 数据 并回应client

void NetMgr::receive_data_from_client(const unsigned char *msg_data) const

{

connect_server *receive_data = (connect_server *)msg_data;

std::cout << "receive from client data is :" << receive_data->content << std::endl;

connect_server_return send_data;

memset(&send_data, 0, sizeof(connect_server_return));

std::string content = receive_data->content;

content += ". server already receive client data, this is server data";

sprintf_s(send_data.content_return, "%s", content.c_str());

std::cout << "server data is :" << send_data.content_return << std::endl;

//使用BitStream 对象来封装数据

RakNet::BitStream stream;

//先写入raknet的消息类型(raknet中自定义类型(ID_USER_PACKET_ENUM))

stream.Write(( RakNet::MessageID )ID_USER_PACKET_ENUM);

//再写入我们自己定义的消息类型

stream.Write(msg_connect_server_return);

//将数据写到stream中,第一个参数是要写入的数据字节数组,第二个是数据的位数

stream.WriteBits((unsigned char *)&send_data , sizeof(connect_server_return) * 8);

//将数据发送到指定的地方

//第一个参数是要发送的bitstream对象

//第二个参数是发送的优先级

//第三个参数是发送的可靠性,这里使用RELIABLE_ORDERED,具体在PacketPriority.h枚举的PacketReliability中有具体说明

//自己看api,这里设置成0

//接收方地址

//是否广播,注意下,要是用那个true,上一个参数就是不需要接受数据的地址

net_peer->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, net_packet->systemAddress, false);

}

最后看看Main.cpp:

#include "NetMgr.h"

#include

int main()

{

NetMgr *p = new NetMgr;

p->init_net_work();

while (true)

{

p->net_work_update();

}

delete p;

p = NULL;

return 0;

}

这里server 和client通信传输的数据我们使用结构体来保存,传输的消息类型在枚举变量中列出。下面这两个头文件client和server工程都都需要。

看看消息类型的头文件:ServerClientMessage.h

#ifndef __SERVERCLIENTMESSAGE_H__

#define __SERVERCLIENTMESSAGE_H__

enum message_type

{

msg_connect_server = 101,

msg_connect_server_return,

};

#endif

保存数据的结构体文件:ServerClientStruct.h

#ifndef __SERVERCLIENTSTRUCT_H__

#define __SERVERCLIENTSTRUCT_H__

#pragma once

#pragma pack(push, 1)

struct connect_server

{

char content[500];

};

#pragma pack(pop)

#pragma pack(push, 1)

struct connect_server_return

{

char content_return[1000];

};

#pragma pack(pop)

#endif

上面的是server端,来看看client端。

NetMgr.h

#ifndef __NETSERVERMGR_H__

#define __NETSERVERMGR_H__

#include

class NetServerMgr

{

public:

NetServerMgr();

~NetServerMgr();

//初始化网络

void init_net_work() const;

//接收网络消息

void net_work_update();

//发送数据给server

void send_data_to_server() const;

//接收server的数据

void receive_data_from_server(const unsigned char *msg_data) const;

private:

//处理server发送过来的消息

void _process_server_message() const;

public:

std::string server_ip;

unsigned short server_port;

};

#endif

NetMrg.cpp

#include "NetServerMgr.h"

#include "../../Source/RakPeerInterface.h"

#include "../../Source/RakNetTypes.h"

#include "../../Source/MessageIdentifiers.h"

#include "../../Source/BitStream.h"

#include

#include "ServerClientMessage.h"

#include "ServerClientStruct.h"

RakNet::RakPeerInterface *net_peer; //网络消息

RakNet::Packet *net_packet; //网络消息包

RakNet::SystemAddress server_address; //server 地址

NetServerMgr::NetServerMgr()

: server_ip("localhost")

, server_port(10001)

{

}

NetServerMgr::~NetServerMgr()

{

}

//初始化网络

void NetServerMgr::init_net_work() const

{

//初始化网络消息

net_peer = RakNet::RakPeerInterface::GetInstance();

if (NULL == net_peer)

{

std::cout << "GetInstance failed" << std::endl;

return;

}

int start_up = net_peer->Startup(1, &RakNet::SocketDescriptor(), 1);

if (start_up > 0)

{

std::cout << "Startup failed" << std::endl;

return;

}

//Connect 连接server

//successful 返回 CONNECTION_ATTEMPT_STARTED

bool rs = (net_peer->Connect(server_ip.c_str(), server_port, NULL, 0, 0) == RakNet::CONNECTION_ATTEMPT_STARTED);

if (!rs)

{

std::cout << "connect server failed" << std::endl;

return;

}

}

//接收网络消息

void NetServerMgr::net_work_update()

{

for (net_packet = net_peer->Receive(); net_packet; net_peer->DeallocatePacket(net_packet), net_packet = net_peer->Receive())

{

switch (net_packet->data[0])

{

case ID_REMOTE_DISCONNECTION_NOTIFICATION:

std::cout << "Another client has disconnected" << std::endl;

break;

case ID_REMOTE_CONNECTION_LOST:

std::cout << "Another client has lost the connection" << std::endl;

break;

case ID_REMOTE_NEW_INCOMING_CONNECTION:

std::cout << "Another client has connected" << std::endl;

break;

//client连接上server后会触发

case ID_CONNECTION_REQUEST_ACCEPTED:

std::cout << "Our connection request has been accepted for server" << std::endl;

server_address = net_packet->systemAddress;

this->send_data_to_server();

break;

case ID_NEW_INCOMING_CONNECTION:

std::cout << "A connection is incoming " << std::endl;

break;

case ID_NO_FREE_INCOMING_CONNECTIONS:

std::cout << "The server is full" << std::endl;

break;

case ID_DISCONNECTION_NOTIFICATION:

std::cout << "A client has disconnected" << std::endl;

break;

case ID_CONNECTION_LOST:

std::cout << "A client lost the connection " << std::endl;

break;

case ID_USER_PACKET_ENUM:

_process_server_message(); //用户自定义消息入口

break;

default:

std::cout << "Message with identifier %d has arrived" << net_packet->data[0] << std::endl;

break;

}

}

}

// server 发送过来的消息

void NetServerMgr::_process_server_message() const

{

int message_id = 0;

RakNet::BitStream bs_in(net_packet->data, net_packet->length, false);

bs_in.IgnoreBytes(sizeof(RakNet::MessageID));

bs_in.Read(message_id);

unsigned char *msg_data = net_packet->data;

msg_data += sizeof(unsigned long) + sizeof(unsigned char);

switch (message_id)

{

case msg_connect_server_return:

this->receive_data_from_server(msg_data);

break;

default:

break;

}

}

// 向 server 发送数据

void NetServerMgr::send_data_to_server() const

{

connect_server send_data;

memset(&send_data, 0, sizeof(connect_server));

sprintf_s(send_data.content, "%s", "hello, this is client send to server");

std::cout << "send to server data is : " << send_data.content << std::endl;

RakNet::BitStream stream;

stream.Write( ( RakNet::MessageID )ID_USER_PACKET_ENUM );

stream.Write( msg_connect_server );

stream.WriteBits((unsigned char *)&send_data , sizeof(connect_server) * 8 );

net_peer->Send( &stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, server_address, false );

}

// 接收 server 回应的数据 并打印出来

void NetServerMgr::receive_data_from_server(const unsigned char *msg_data) const

{

connect_server_return *receive_data = (connect_server_return *)msg_data;

std::cout << "receive from server data is :" << receive_data->content_return << std::endl;

}

Main.cpp

#include "NetServerMgr.h"

#include

int main()

{

NetServerMgr *p = new NetServerMgr;

p->init_net_work();

while (true)

{

p->net_work_update();

}

delete p;

p = NULL;

return 0;

}

运行程序的时候,需要将RakNet_DLL_Debug_Win32.dll放到exe所在的目录下面。开启server,再开启client测试下:

由于server和client其实代码都差不过,注释就写了server的,感觉还是比较详细了,要是想深入了解,可以使用的时候直接查看里面的api文档。

发送数据的时候,先添加raknet的消息类型(就是ID_USER_PACKET_ENUM),再添加我们自定义的(这里是struct),最后添加实际数据。

接受的时候,要先偏移掉raknet的消息类型,这里其实一个char的大小,再偏移掉自定义的枚举消息类型,这里其实是整形,就可以获得实际的传输数据。发送的封包和解包是一个逆向的过程。

相关推荐

365体育手机版中国官方网站 LOL刀锋女皇莫甘娜多少钱 皮肤价格 特效及重做对比
365bet网址是多少 波兰铁锤马尔钦

波兰铁锤马尔钦

📅 07-08 👁️ 7307
365bet亚洲真人网址 斋的成语

斋的成语

📅 07-13 👁️ 2909