一个使用超简单C++封装的网络库(包含服务器端和客户端,跨平台,比较适用于移动终端)

yu505710025 2015-07-30 09:41:56
简介:

其实就只是对网络底层的一个封装,将一些回调全部都已经封装好,直接指定相应的回调函数就可以对收到的数据包进行处理。

个人觉得该网络库比较方便的地方就是可以直接将所有自定义及C++标准库容器直接发送到服务端,而原始的C函数发送时连续存储的内存。

注意,该库使用C11编译,所以客户端必须支持C11,废话不多说下面直接看使用demo。


服务器与客户端的相关协议定义(protocols.h)

#pragma once
#include "protocolbase.h"


//客户端请求登录
class QLogin :public Net::ProtocolBase
{
public:
QLogin() = default;
~QLogin() = default;

Serialize(QLogin)
{
ar(uClientId, strUsername, strPassword);
}

Net::UInt32 uClientId;
std::string strUsername;
std::string strPassword;
};

//客户端请求数据
class QData :public Net::ProtocolBase
{
public:
QData() = default;
~QData() = default;

Serialize(QData)
{

}
};


//响应客户端登录
class RLogin :public Net::ProtocolBase
{
public:
RLogin() = default;
~RLogin() = default;

Serialize(RLogin)
{
ar(strErrorInfo);
}

std::string strErrorInfo;
};

class CustomData
{
public:
CustomData() = default;
~CustomData() = default;

Serialize(CustomData)
{
ar(nData, fData, dData, shData);
}

int nData;
float fData;
double dData;
short shData;
};


//响应客户端请求数据
class RData :public Net::ProtocolBase
{
public:
RData() = default;
~RData() = default;

Serialize(RData)
{
ar(strNickname, bSex, uAge, strEmail, vData, mData, customData);
}

std::string strNickname;
bool bSex;
Net::UInt8 uAge;
std::string strEmail;
std::vector<std::string> vData;
std::map<std::string,std::pair<int,float> > mData;
CustomData customData;
};




服务端代码(server.cpp)
#include "socketserver.h"
#include "socketclient.h"

#include "protocols.h"

#include <iostream>


class ServerSocketSession :public Net::SocketSession
{
public:
ServerSocketSession() = default;
~ServerSocketSession()
{

}
ServerSocketSession(const ServerSocketSession&) = delete;
ServerSocketSession& operator = (const ServerSocketSession&) = delete;

//响应用户登录
void userLogin(std::shared_ptr<QLogin> r)
{
auto result = std::make_shared<RLogin>();
if (r->uClientId == 123456 &&
r->strUsername == "123456" &&
r->strPassword == "123456")
{
result->strErrorInfo = "LoginSucceed";
}
else
{
result->strErrorInfo = "LoginFailure";
}
send(result);
}

//响应用户请求详细数据
void userData(std::shared_ptr<QData> r)
{
auto result = std::make_shared<RData>();

result->strNickname = "winter";
result->bSex = true;
result->strEmail = "winter@gmail.com";
result->uAge = 100;
result->mData.emplace("m1",std::make_pair(1111,111.111f));
result->mData.emplace("m2", std::make_pair(2222, 222.222f));
result->mData.emplace("m3", std::make_pair(3333, 333.333f));

result->vData.push_back("v1");
result->vData.push_back("v2");
result->vData.push_back("v3");
result->vData.push_back("v4");

result->customData.dData = -10000000.000001f;
result->customData.fData = 100000.00002f;
result->customData.nData = -100000;
result->customData.shData = -100;
send(result);
}
};

客户端代码(client.cpp)
#include "socketserver.h"
#include "socketclient.h"


#include "protocols.h"


#include <iostream>
class ClientSocketSession
{
public:
ClientSocketSession()
:m_socketClient("127.0.0.1", 6691, true)
{
m_socketClient.registerProtocol(&ClientSocketSession::onUserLogin, this);
m_socketClient.registerProtocol(&ClientSocketSession::onUserData, this);
m_socketClient.registerProtocol(&ClientSocketSession::onSocketEvent, this);


m_socketClient.connect();
}


~ClientSocketSession() = default;
ClientSocketSession(const ClientSocketSession&) = delete;
ClientSocketSession& operator = (const ClientSocketSession&) = delete;

void update(){ m_socketClient.update(); }

void onSocketEvent(std::shared_ptr<Net::SocketEvent> r, Net::SocketClient::ErrorCode e)
{
if (e == Net::SocketClient::ErrorCode::kSucceed && r->getEvent() == Net::SocketEvent::Event::kConnect)
{
std::cout << "Connect succeed! " << r->getInfo() << std::endl;

auto qlogin = std::make_shared<QLogin>();
qlogin->uClientId = 11111;
qlogin->strUsername = "11111";
qlogin->strPassword = "11111";
m_socketClient.send(qlogin);
}
else
{
if (r->getEvent() == Net::SocketEvent::Event::kConnect)
{
std::cout << "Connect: "<< r->getInfo() << std::endl;
}
else
{
std::cout << "DisConnect: " << r->getInfo() << std::endl;
}

}
}


void onUserLogin(std::shared_ptr<RLogin> r, Net::SocketClient::ErrorCode e)
{
if (r->strErrorInfo == "LoginSucceed")
{
auto qdata = std::make_shared<QData>();
for (size_t i = 0; i < 10; i++)
{
m_socketClient.send(qdata);
}
}
else if (r->strErrorInfo == "LoginFailure")
{
auto qlogin = std::make_shared<QLogin>();
qlogin->uClientId = 123456;
qlogin->strUsername = "123456";
qlogin->strPassword = "123456";
m_socketClient.send(qlogin);
}

}

void onUserData(std::shared_ptr<RData> r, Net::SocketClient::ErrorCode e)
{
std::cout << "Nickname: " << r->strNickname << std::endl;
std::cout << "Sex: " << (r->bSex ? "true": "false") << std::endl;
std::cout << "Age: " << (int)r->uAge << std::endl;
std::cout << "Email: " << r->strEmail << std::endl;

for (auto data : r->vData)
{
std::cout << "vData: " << data << std::endl;
}

for (auto data : r->mData)
{
std::cout << "vData:" << data.first << ":" << data.second.first << ":" << data.second.second << std::endl;
}


std::cout << "customData.nData: " << r->customData.nData << std::endl;
std::cout << "customData.fData: " << r->customData.fData << std::endl;
std::cout << "customData.dData: " << r->customData.dData << std::endl;
std::cout << "customData.shData: " << r->customData.shData << std::endl;
}

private:

Net::SocketClient m_socketClient;
};

下面是调用代码
auto server = Net::SocketServer::createInstance<ServerSocketSession>("127.0.0.1", 6691, 1,true);
server->registerProtocol(&ServerSocketSession::userLogin);
server->registerProtocol(&ServerSocketSession::userData);

ClientSocketSession clientSession;


//一个简单的主循环
bool bExit(true);
while (bExit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));

//在客户端的每一帧需要调用以下函数。
clientSession.update();
}


return 0;



http://download.csdn.net/download/yu505710025/8944083 这里是完整demo。
...全文
2252 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
yu505710025 2015-07-30
  • 打赏
  • 举报
回复
引用 3 楼 jiqiang01234 的回复:
模拟boost::serialization库?
cereal-1.1.2 跟boost::serialization原理差不多,只不过是轻量级的。
jiqiang01234 2015-07-30
  • 打赏
  • 举报
回复
模拟boost::serialization库?
yu505710025 2015-07-30
  • 打赏
  • 举报
回复
google protocol buffer 只是一个序列化库,且不支持C++标准库容器的。这个支持任何自定义数据结构。
jiqiang01234 2015-07-30
  • 打赏
  • 举报
回复
模拟google protocol buffer?
1、本课程是一个干货课程,主要讲解如何封装服务器底层,使用Tcp/ip长连接,IDE使用vs2019 c++开发以及使用c++11的一些标准,跨平台windows和linux,服务器性能高效,单服务器压力测试上万无压力,服务器框架是经历过上线产品的验证,框架简单明了,不熟悉底层封装的人,半个小时就能完全掌握服务器框架上手写业务逻辑。2、本课程是一个底层服务器框架教程,主要是教会学员在windows或linux下如何封装一个高效的,避免踩坑的商业级框架,服务器底层使用初始化即开辟内存的技术,使用内存池,服务器运行期间内存不会溢出,非常稳定,同时服务器使用自定义哈希hashContainer,在处理新的连接,新的数据,新的封包,以及解包,发包,粘包的过程,哈希容器性能非常高效,增、删、查、改永远不会随着连接人数的上升而降低性能,增、删、查、改的复杂度永远都是恒定的O(1)。3、服务器底层封装没有使用任何第三方网络以及任何第三方插件,自由度非常的高,出了任何BUG,你都有办法去修改,查找问题也非常方便,在windows下使用iocp,linux下使用epoll.4、讲解c++客户端,主要用于服务器之间通信,也就是说你想搭建多层结构的服务器,服务器与服务器之间使用socket通信。还可以使用c++客户端做压力测试,开辟多线程连接服务器,教程提供了压力测试,学员可以自己做压力测试服务器性能。5、赠送ue4和unity3d通信底层框架以及多人交互demo,登录,注册,玩家离开,同步主要是教会学员服务器与客户端如何交互。6、赠送c++连接mysql数据框架demo,登录,注册,玩家离开数据持久化.7、服务器教程使用自定义通信协议,同时也支持protobuf,选择权在开发者自己手里,想用什么协议都可以,自由度高。8、服务器教程使用手动敲代码逐句讲解的方式开展教学课程。非喜勿喷,谢谢大家。9、服务器教程提供源码,大家可以在平台提供的地址下载或者联系我,服务器使用c++11部分标准,std::thread,条件变量,线程锁,智能指针等,需要学员具备一定c++知识,购买前请慎重考虑。

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧