大家好,欢迎来到IT知识分享网。
一、Muduo网络库简介
Muduo网络库:底层实质上为Linux的epoll + pthread线程池,且依赖boost库。 muduo的网络设计核心为一个线程一个事件循环,有一个main Reactor负载accept连接,然后把连接分发到某个sub Reactor(采用轮询的方式来选择sub Reactor),该连接的所用操作都在那个sub Reactor所处的线程中完成。多个连接可能被分派到多个线程中,以充分利用CPU,Reactor poll的大小是固定的,根据CPU的数目确定。如果有过多的耗费CPU I/O的计算任务,可以提交到创建的ThreadPool线程池中专门处理耗时的计算任务。
二、服务器编程实例
muduo网络库实质为: epoll + 线程池,优点是能够将网络I/O的代码和业务代码分开。 而业务代码主要分为:用户的连接和断开、用户的可读写事件两类。至于什么时候发生这些事件,由网络库进行上报,如何监听这些事件,都是网络库所封装好的,我们就可以快速进行项目开发。
2.1 环境配置
以上环境安装好后,因为我们使用的为第三方库,代码编译完成后需要链接相应的.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 + ]),连接断开,可以看到服务器也能够正常退出。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/112797.html








