当前位置: 首页 > news >正文

集群聊天服务器项目【C++】(三)muduo库的简单介绍

在上一讲中介绍了Json库的相关知识,本次接着介绍muduo库的相关内容,这些知识在本项目中都会使用到。

1.muduo库简介

muduo库顶层就是epoll(IO复用技术) + Linux的pthread多线程,所以只能安装在Linux系统中。此外它依赖Boost库,相关的安装已经在我的博客中写出环境配置。

muduo 的线程模型为「one loop per thread + threadPool」模型。一个线程对应一个事件循环(EventLoop),也对应着一个 Reactor 模型。EventLoop 负责 IO 和定时器事件的分派。
其中有 mainReactor 和 subReactor。mainReactor通过Acceptor接收新连接,然后将新连接派发到subReactor上进行连接的维护。这样mainReactor可以只专注于监听新连接的到来,而从维护旧连接的业务中得到解放。同时多个Reactor可以并行运行在多核 CPU 中,增加服务效率。因此我们可以通过 muduo 快速完成网络模块。

如果不使用muduo库,我们想设计一个高并发的服务器,就需要使用epoll+线程池技术,手动创建epoll对象,然后在主线程注册监听连接的fd读事件,用来管理新客户的连接,如果有新连接进来就在线程池中选一个线程处理该客户的相关操作。因此主线程去管理新客户的连接,子线程去处理客户的读写事件和业务操作。
因此使用muduo库,可以让我们只关注业务模块(处理客户的读写相关事件),而不去关心网络IO模块,从而提高效率。

2.muduo库的使用

muduo库提供了两个主要的类:

  1. TcpServer:用于编写服务器程序
  2. TcpClient:用于编写客户端程序

基于muduo网络库开发服务器程序:

  1. 组合TcpServer对象
  2. 创建EventLoop事件循环对象的指针
  3. 明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
  4. 在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写时间的回调函数
  5. 设置合适的服务端线程数量,muduo库会自己分配I/O线程和worker线程
/*
muduo网络库给用户提供了两个主要的类
TcpServer : 用于编写服务器程序的
TcpClient : 用于编写客户端程序的epoll + 线程池
好处:能够把网络I/O的代码和业务代码区分开用户的连接和断开       用户的可读写事件
*/
#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;class ChatServer
{
public:ChatServer(EventLoop *loop,               // 事件循环const InetAddress &listenAddr, // IP+Portconst string &nameArg)        //服务器名字: _server(loop, listenAddr, nameArg), _loop(loop){// 给服务器注册用户连接的创建和断开回调_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));// 给服务器注册用户读写事件回调_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));// 设置服务器端的线程数量 1个I/O线程   3个worker线程(自动分配)_server.setThreadNum(4);}//开启事件循环void start(){_server.start();}private:// 专门处理用户的连接创建和断开  epoll listenfd acceptvoid 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(); // close(fd)// _loop->quit();}}// 专门处理用户的读写事件void onMessage(const TcpConnectionPtr &conn, // 连接Buffer *buffer,               // 缓冲区Timestamp time)               // 接收到数据的时间信息{string buf = buffer->retrieveAllAsString();  //转成stringcout << "recv data:" << buf << " time:" << time.toFormattedString() << endl;conn->send(buf);  //}TcpServer _server; // #1EventLoop *_loop;  // #2 epoll
};int main()
{EventLoop loop; // epollInetAddress addr("127.0.0.1", 6000);ChatServer server(&loop, addr, "ChatServer");server.start(); // listenfd epoll_ctl添加到epoll上loop.loop();    // epoll_wait以阻塞方式等待新用户连接,已连接用户的读写事件等
}

3.编译和运行

muduo库依赖muduo_net.so、muduo_base.so、pthread.so三个动态链接库

3.1g++编译运行

g++ -o server muduo_server.cpp -lmuduo_net -lmuduo_base -lpthread

注意:-lmuduo_net写在前面,因为muduo_base依赖muduo_net
在这里插入图片描述

3.2vscode编译运行

在vscode里修改编译配置信息:ctrl + shift + b选择g++的哪个,在"args"中增加三个动态库链接:
在这里插入图片描述
在muduo_server.cpp里ctrl + shift + b点击编译代码,结果如下:
在这里插入图片描述
可以看到args都现显示在/usr/bin/g++ 后面,由vscode自动编译。

总结

我们使用muduo库,因为它封装了epoll和多线程,因此可以用它来处理网络IO模块,我们只需要关心业务模块,大大提高了工作效率。
业务模块只需要我们注册两个回调函数:setConnectionCallback和setMessageCallback,这样我们就能将网络IO模块和业务模块解耦。
最后编译链接后运行代码,代码正常无误。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 网页模板该怎么选
  • MVC 控制器
  • Java | Leetcode Java题解之第401题二进制手表
  • yolov8 rect batch_shapes 672 图像大小变化
  • PHP智驭未来悦享生活智慧小区物业管理小程序系统源码
  • Java的发展史与前景
  • SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者
  • 4G模块、WIFI模块、NBIOT模块通过AT指令连接华为云物联网服务器(MQTT协议)
  • 高效数据移动指南 | 如何快速实现数据库 MySQL 到 MongoDB 的数据同步?
  • Python selenium 破解腾讯滑块行为验证码
  • 【Hadoop|MapReduce篇】Hadoop序列化概述
  • 【运维监控】influxdb 2.0+grafana 监控java 虚拟机以及方法耗时情况(完整版)
  • RTC、ADC
  • 深入理解Python函数参数传递:可变与不可变对象的实战解析20240914
  • Web安全与网络安全:SQL漏洞注入
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【技术性】Search知识
  • 【知识碎片】第三方登录弹窗效果
  • ES6 学习笔记(一)let,const和解构赋值
  • HTTP请求重发
  • Joomla 2.x, 3.x useful code cheatsheet
  • Protobuf3语言指南
  • Python进阶细节
  • 多线程 start 和 run 方法到底有什么区别?
  • 坑!为什么View.startAnimation不起作用?
  • 来,膜拜下android roadmap,强大的执行力
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • 组复制官方翻译九、Group Replication Technical Details
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • # .NET Framework中使用命名管道进行进程间通信
  • # 计算机视觉入门
  • # 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
  • #Spring-boot高级
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (1)(1.13) SiK无线电高级配置(五)
  • (libusb) usb口自动刷新
  • (面试必看!)锁策略
  • (十)Flink Table API 和 SQL 基本概念
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • *算法训练(leetcode)第四十天 | 647. 回文子串、516. 最长回文子序列
  • ./configure,make,make install的作用
  • .aanva
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .Net Core 生成管理员权限的应用程序
  • .net(C#)中String.Format如何使用
  • .NetCore+vue3上传图片 Multipart body length limit 16384 exceeded.
  • .NET单元测试
  • .NET中使用Protobuffer 实现序列化和反序列化
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @Autowired多个相同类型bean装配问题
  • @ModelAttribute注解使用