IT评测·应用市场-qidao123.com技术社区
标题:
C++Muduo网络库:简介及使用
[打印本页]
作者:
徐锦洪
时间:
2024-8-6 11:59
标题:
C++Muduo网络库:简介及使用
一、Muduo网络库简介
Muduo网络库:底层实质上为Linux的epoll + pthread线程池,且依靠boost库。
muduo的网络筹划核心为一个线程一个事件循环,有一个main Reactor负载accept毗连,然后把毗连分发到某个sub Reactor(采用轮询的方式来选择sub Reactor),该毗连的所用操作都在那个sub Reactor所处的线程中完成。多个毗连大概被分派到多个线程中,以充分使用CPU,Reactor poll的大小是固定的,根据CPU的数量确定。如果有过多的泯灭CPU I/O的计算使命,可以提交到创建的ThreadPool线程池中专门处置惩罚耗时的计算使命。
关于Reactor模型详解可参考此篇博客:高性能网络服务器底子
一般我们见到的高并发网络模型如下,有一个I/O线程(epoll),专门处置惩罚新用户链接;新用户链接完成后通过特定算法分发给不同的工作线程,线程数一般与CPU核数对等,工作线程专门处置惩罚已链接用户的读写事件。
二、服务器编程实例
muduo网络库实质为:
epoll + 线程池,优点是能够将网络I/O的代码和业务代码分开。
而业务代码主要分为:用户的毗连和断开、用户的可读写事件两类。至于什么时间发生这些事件,由网络库进行上报,如何监听这些事件,都是网络库所封装好的,我们就可以快速进行项目开发。
muduo给用户提供了两个主要的类:
1、TcpServer:用于编写服务器程序。
2、TcpClient:用于编写客户端程序。
2.1 情况设置
我们是vscode远程在Linux上进行开发的,需要提前安装好muduo网络库,搭建vscode远程开发情况,如下:
1、moduo库安装:Linux平台下muduo网络库源码编译安装
2、vscode远程情况设置:windows+vscode搭建远程linux开发情况
以上情况安装好后,由于我们使用的为第三方库,代码编译完成后需要链接相应的.so库,可以通过以下两种不同的方式进行链接:
1、我们可以在终端上通过命令方式手动进行链接相应库文件,如下:
2、按F1调出vscode编译设置文件c_cpp_properties.json,依据自己需要修改设置。
也可以按ctrl + shift + b,点击齿轮。
进入task.json依据自己需要设置链接库。
2.2 服务器编程
muduo库服务器编程流程:
1、组合TcpServer对象;
2、创建EventLoop事件循环对象的指针,可以向loop上注册感兴趣的事件,相应事件发生loop会上报给我们;
3、明确TcpServer构造函数需要的参数,输出服务器对应类的构造函数;
TcpServer(EventLoop* loop, //事件循环
const InetAddress& listenAddr, //绑定IP地址 + 端口号
const string& nameArg, //TcpServer服务器名字
Option option = kNoReusePort); //tcp协议选项
复制代码
4、在当前服务器类的构造函数中,注册处置惩罚毗连断开的回调函数和处置惩罚读写事件的回调函数主要通过下面两个函数回调实现;
void setConnectionCallback(const ConnectionCallback& cb) //链接的创建与断开
{ connectionCallback_ = cb; }
void setMessageCallback(const MessageCallback& cb) //消息读写事件
{ messageCallback_ = cb; }
复制代码
5、设置合适的服务器端线程数量,muduo会自动分配I/O线程与工作线程;
6、开启事件循环start();
muduo服务器端编程代码如下:
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
#include <string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;
//基于muduo网络库开发服务器程序
class ChatServer
{
public:
//3、明确TcpServer构造函数需要的参数,输出服务器对应类的构造函数
ChatServer(EventLoop *loop, const InetAddress &listenAddr, const string &nameArg) //事件循环、IP+port、服务器名字
: _server(loop, listenAddr, nameArg), _loop(loop)
{
//4.1、注册用户连接的创建和断开事件的回调
_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1)); //利用绑定器绑定成员方法onConnection,保持参数与muduo库函数参数一致
//4.2、注册用户读写事件的回调
_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3)); //利用绑定器绑定成员方法onMessage,保持参数与muduo库函数参数一致
//5、设置服务器端的线程数量
_server.setThreadNum(4);
}
//6.开启事件循环
void start()
{
_server.start();
}
private:
//4.1 专门处理用户的连接和断开
void onConnection(const TcpConnectionPtr &conn) //连接
{
if (conn->connected())
{
cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:online" << endl;
}
else
{
cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:offline" << endl;
conn->shutdown(); //连接断开将socket资源释放
//或者调用_loop->quit()退出epoll;
}
}
//4.2 专门处理用户读写事件
void onMessage(const TcpConnectionPtr &conn, Buffer *buffer, Timestamp time) //连接、缓冲区、接收到数据的事件信息
{
string buf = buffer->retrieveAllAsString(); //将接收数据全部放入字符串中
cout << "recv data:" << buf << " time:" << time.toString() << endl;
conn->send(buf); //收到什么数据发回去什么数据
}
TcpServer _server; //1、组合TcpServer对象
EventLoop *_loop; //2、创建EventLoop事件循环对象的指针
};
int main()
{
EventLoop loop; //epoll
InetAddress addr("127.0.0.1", 6000);
ChatServer server(&loop, addr, "ChatServer");
server.start(); //启动服务:listenfd通过epoll_ctl添加到epoll上
loop.loop(); //类似于epoll_wait以阻塞的方式等待新用户连接或处理已连接用户的读写事件
return 0;
}
复制代码
2.3 运行及测试
我们调用了muduo第三方库,因此代码编译完成后还需要链接相应库文件,muduo_net必须写在muduo_base前面(muduo_base依靠了muduo_net库),命令如下:
执行程序./server,我们新打开一个终端充当客户端,发送相应数据可以看到服务器可以正常回显。
此时我们客户端进行退出(telnet退出为ctrl + ]),毗连断开,可以看到服务器也能够正常退出。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4