一,asio2 网络库 介绍
简单理解 asio2 是一个支持 tcp, udp, http, websocket, rpc, ssl, icmp, serial_port的c++第三方库。项目需要,目前我仅仅用到了rpc 这部分功能,使用它来替换QtRo 实现进程间通信,QtRo 用起来太麻烦,需要接口文件,并称生成对应的代码,还要去继承,实现。这个相对简单点。
https://github.com/zhllxt/asio2
二,使用
甭管是客户端还是服务端,定义好 函数后,通过bind 绑定,之后 对端 就可以异步调用了(async_call)。
(1),客户端
//连接服务端
bool RPCClient::run(std::string_view host,std::string_view port)
{
client.set_default_timeout(std::chrono::seconds(20));
client.bind_connect([&]()
{
if (asio2::get_last_error())
return;
if (client.is_started())
{
ASIO2_ASSERT(asio2::get_last_error() == rpc::error::in_progress);
}
else
{
ASIO2_ASSERT(asio2::get_last_error() == rpc::error::not_connected);
}
});
bind();
return client.start(host, port);
}
//绑定需要提供给服务端的函数
void RPCClient::bind()
{
client.bind("receiveCloudNormal",&RPCClient::receiveCloudNormal,this);
client.bind("receiveRun",&RPCClient::receiveRun,this);
client.bind("receiveStop",&RPCClient::receiveStop,this);
client.bind("receiveImg",&RPCClient::receiveImg,this);
}
//处理具体的业务
void RPCClient::receiveRun()
{
std::cout<<"receiveRun "<<" time:"<<getTime()<<std::endl;
}
//调用服务端函数
void RPCClient::sendIsCollision(bool collision)
{
client.async_call("receiveIsCollision", collision).response([](long long _time){
std::cout<<"sendIsCollision response: "<<" time:"<<_time<<std::endl;
});
std::cout<<"sendIsCollision "<<" time:"<<getTime()<<std::endl;
}
(2)服务端
//监听 ip 端口
bool RPCServer::run(std::string_view host,std::string_view port)
{
server.bind_connect([&](auto & session_ptr)
{
std::cout<<"client enter : "<<session_ptr->remote_address().c_str()<<" "<< session_ptr->remote_port()<<" "<<session_ptr->local_address().c_str()<<" "<< session_ptr->local_port()<<endl;
}).bind_start([&]()
{
cout<<"start rpc server : "<<server.listen_address().c_str()<<" "<< server.listen_port()<<" "<<asio2::last_error_val()<<" "<< asio2::last_error_msg().c_str()<<endl;
});
bind();
return server.start(host, port);
}
//绑定提供给 客户端的函数
void RPCServer::bind()
{
server.bind("receiveIsCollision",&RPCServer::receiveIsCollision,this);
}
//访问客户端函数
void RPCServer::sendRun()
{
server.async_call("receiveRun");
std::cout<<"sendRun "<<" time:"<<getTime()<<std::endl;
}
三, 注意
(1),如何发送图片,比如opencv Mat
这个库 只支持c++ 内置类型,因此所有自定义类型,最好都要转成c++ 内置类型,发送图片是将mat 编码到了 string里。
//自定义图片 结构体
struct Img
{
std::string piexl;
template <class Archive>
void serialize(Archive & ar)
{
ar(piexl);
}
};
//发送图片进行编码
void Widget::on_sendImg_clicked()
{
if(!imgFile.isEmpty()){
cv::Mat image = imread(imgFile.toStdString().c_str());
RPCData::Img img;
std::vector<unsigned char> buff;
cv::imencode(".png", image, buff);
img.piexl.resize(buff.size());
memcpy(&img.piexl[0], buff.data(), buff.size());
server->sedImg(img);
}
}
//收到图片进行解码
void RPCClient::receiveImg(RPCData::Img img)
{
std::cout<<"receiveImg "<< img.piexl.size()<< " time:"<<getTime()<<std::endl;
cv::Mat dstImg(1,img.piexl.size(), CV_8U,(char*)img.piexl.data());
cv::Mat dst = cv::imdecode(dstImg, CV_LOAD_IMAGE_COLOR);
imwrite ("dstImg.png",dst);
}
(2),如何发送点云
//自定义点云 结构体
struct Point{
Point(){
x=0.0;
y=0.0;
z=0.0;
}
Point(float _x,float _y,float _z){
x=_x;
y=_y;
z=_z;
};
float x;
float y;
float z;
template <class Archive>
void serialize(Archive & ar)
{
ar(x);
ar(y);
ar(z);
}
};
struct CloudNormal{
std::vector<Point> points;
template <class Archive>
void serialize(Archive & ar)
{
ar(points);
}
};