C++项目——集群聊天服务器项目(三)muduo网络库

今天来介绍集群聊天器项目中网络模块代码的核心模块——muduo网络库,一起来看看吧~

环境搭建C++项目——集群聊天服务器项目(一)项目介绍、环境搭建、Boost库安装、Muduo库安装、Linux与vscode配置-CSDN博客

Json第三方库C++项目——集群聊天服务器项目(二)Json第三方库-CSDN博客

一、muduo网络库介绍

muduo由陈硕大佬开发,是一个基于非阻塞IO和事件驱动的C++高并发TCP网络库

网络设计:reactors in threads - one loop per thread

one loop per thread指的是:

(1)一个线程只能有一个事件循环(EventLoop)

(2)一个文件描述符只能由一个线程进行读写,即一个TCP连接必须归属于某个EventLoop管理。

方案的特点是one loop per thread,有一个main reactor负载accept连接,然后把连接分发到某个sub reactor,该连接的所用操作都在那个sub reactor所处的线程中完成。

多个连接可能被分派到多个线程中,以充分利用CPU。

 Reactor poll的大小是固定的,根据CPU的数目确定。

原理:一个Base IO thread负责accept新的连接,接收到新的连接以后,使用轮询的方式在reactor pool中找到合适的sub reactor将这个连接挂载上去,这个连接上的所有任务都在这个sub reactor上完成。

如果有过多的耗费CPU I/O的计算任务,可以提交到创建的ThreadPool线程池中专门处理耗时的计算任务。

将epoll和线程池封装起来,好处是能够把网络的I/O代码与业务代码区分开

二、muduo网络库主要的类

TcpServer:用于编写服务器程序的类

TcpClient:用于编写客户端程序的类

接下来使用muduo网络库开发一个基本的服务器程序

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

3.1 基本步骤

1.组合TcpServer对象

2.创建EventLoop事件循环对象的指针

3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数

4.在当前服务器类的构造函数中,注册处理连接和读写事件的回调函数

5.设置合适的服务端线程数量,muduo会自动划分I/O线程和worker线程

3.2 代码

 头文件

#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;

组合TcpServer对象

创建EventLoop事件循环对象的指针

明确TcpServer构造函数需要什么参数

class ChatServer
{
public:ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆const InetAddress& listenAddr,      //IP和端口const string& nameArg)              //服务器的名字: _server(loop, listenAddr, nameArg), _loop(loop){}
private:TcpServer _server;EventLoop *_loop;       //epoll
};

输出ChatServer的构造函数

构造函数负责给服务器注册用户连接与断开回调函数,注册读写事件回调函数,并设置线程数量,muduo网络库会自动分配线程用于主reactor和子reactor

 ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆const InetAddress& listenAddr,      //IP和端口const 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();}

连接与断开回调函数:显示上线和下线

    //专门处理用户连接创建和断开    epollvoid 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();}}

读写事件回调函数:这里的功能是将客户端发来的信息发回去

    //专门处理用户读写事件    void OnMessage(const TcpConnectionPtr&conn ,    //连接Buffer*buffer,            //缓冲区Timestamp time)          //接受到数据的时间信息{         string buf = buffer->retrieveAllAsString();cout << "recv data : " << buf << " time:" << time.toString() << endl;conn->send(buf);}

main函数

int main(){EventLoop loop; //epollInetAddress addr("127.0.0.1",6000);ChatServer server(&loop,addr,"ChatServer");server.start();         loop.loop();        //epoll_wait以阻塞方式等待新用户连接或读写事件等return 0;}

全部代码:

/*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;/*基于muduo网络库开发服务器程序
1.组合TcpServer对象
2.创建EventLoop事件循环对象的指针
3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
4.在当前服务器类的构造函数中,注册处理连接和读写事件的回调函数
5.设置合适的服务端线程数量,muduo会自动划分I/O线程和worker线程
*/
class ChatServer
{
public:ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆const InetAddress& listenAddr,      //IP和端口const 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://专门处理用户连接创建和断开    epollvoid 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();}}//专门处理用户读写事件    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;EventLoop *_loop;       //epoll
};int main(){EventLoop loop; //epollInetAddress addr("127.0.0.1",6000);ChatServer server(&loop,addr,"ChatServer");server.start();         loop.loop();        //epoll_wait以阻塞方式等待新用户连接或读写事件等return 0;}

3.3 服务器程序执行

3.3.1 g++编译

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

终端输入上述语句,其中,g++ -I头文件搜索路径 -L库文件搜素路径 -l库名称,执行server文件,结果如下:

可以看到客户端登录成功后,信息成功回显!

telnet 127.0.0.1 6000

3.3.2 CMake编译

可以查看Linux环境下是否有CMake,有muduo库其实就已经有CMake了,通过下面的命令查看版本号

cmake -version

在3.2文件的同级目录下,创建CMakeLists.txt文件,分别写出编译选项、需要编译的源文件列表、可执行文件存储的路径、生成可执行文件、以及链接的库文件

cmake_minimum_required(VERSION 3.0)
project(main)# 配置编译选项
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)  # 可调试可执行文件#配置头文件搜索路径
# include_directories()#配置库文件搜索路径
# link_directories()# 设置需要编译的源文件列表
set(SRC_LIST ./muduo_server.cpp)
# 设置可执行文件存储的路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)# 把.指定路径下的所有源文件放入SRC_LIST变量名中
# aux_source_directory(.SRC_LIST)# 表示生成可执行文件server,由SRC_LIST变量定义的源文件而来
add_executable(server ${SRC_LIST})  # 生成可执行文件#表示server这个目标程序,需要链接muduo_net muduo_base pthread库文件
target_link_libraries(server muduo_net muduo_base pthread)

可以看到,这里将可执行文件放在了项目文件的bin文件夹下,执行server文件同样回显相同的结果

至此,muduo网络库的示例代码与实验完毕,期待后续项目的更新把~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/768726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nodejs版本管理工具nvm

官网地址 https://github.com/coreybutler/nvm-windows/releases 下载1.1.12版本&#xff0c;使用图形化安装。 参考这篇文章&#xff1a; https://blog.csdn.net/m0_46491549/article/details/129750694 一步到位——Node版本管理神器nvm安装教程&#xff08;2024最新&#x…

Linux的介绍以及其发展历史

文章目录 前言一、技术是推动社会发展的基本动力1.人为什么能成为万物之长呢&#xff1f;2.人为什么要发明工具&#xff0c;进行进化呢&#xff1f;3.人是如何发明工具的&#xff1f;4.为什么要有不同的岗位和行业&#xff1f; 二、计算机(操作系统)发展的基本脉络1.第一台计算…

Xilinx高级调试方法--多卡调试

Xilinx高级调试方法--多卡调试 1 测试工程2 驱动修改3 工程测试 本文主要介绍基于XVC技术实现多卡调试的方法 1 测试工程 加速卡1 Verdor ID&#xff1a;1BD4Device ID&#xff1a;903E 加速卡2 Verdor ID&#xff1a;1BD4Device ID&#xff1a;903F 2 驱动修改 为了同时识…

智能小程序开发 —— P2P SDK 源码介绍(二)

ty.p2p.uploadFile P2P上传文件 需引入P2PKit&#xff0c;且在>0.0.1版本才可使用 参数 Object object 属性类型默认值必填说明deviceIdstring是设备idalbumNamestring是albumName 和设备端约定字段filePathstring是文件本地路径extDatastring否扩展字段extDataLengthnum…

基于PyTorch深度学习实战入门系列-PyTorch基础全

Torch的基本使用 判断GPU是否可用 torch.cuda.is_available()张量 Torch 定义了 10 种张量类型&#xff0c;包括 CPU 和 GPU 形式&#xff0c;如下表所示&#xff1a; 数据类型dtypeCPU张量GPU张量32位浮点数torch.float32、torch.floattorch.FloatTensortorch.cuda.FloatTenso…

大数据技术原理与应用 01.大数据概述

不可以垂头丧气&#xff0c;会显矮 —— 24.3.24 参考学习&#xff1a;厦门大学 林子雨老师 大数据技术原理与应用 一、大数据时代 大数据概念、影响、应用、关键技术 大数据与云计算、物联网的关系 ①三次信息化浪潮时代 ②第三次信息化浪潮的技术支撑 1>存储设备容量不断…

ARM:按键中断

key_inc.c #include"key_inc.h"void key1_it_config(){//使能GPIOF外设时钟RCC->MP_AHB4ENSETR | (0x1<<5);//将PF9设置为输入模式GPIOF->MODER & (~(0x3<<18));//设置由PF9管脚产生EXTI9事件EXTI->EXTICR3 & (~(0XFF<<8));EXTI…

msyq类型类转换造成索引失效

今天碰到一个慢sql的问题&#xff0c;sql明明按照最前缀的原则写的&#xff0c;但是索引就是不生效&#xff0c;最终排查发现是因为索引字段发生类型转换造成的。 一、表结构 1、表字段 2、表索引 二、问题sql EXPLAIN SELECT * FROM t_res WHERE open 1 AND res_date &…

蓝桥杯day12刷题日记

P8720 [蓝桥杯 2020 省 B2] 平面切分 思路&#xff1a;首先借用dalao的图解释一下&#xff0c;又多出一条与当前平面任意一条直线都不重合线时&#xff0c;多了的平面是交点数1&#xff0c;所以用双层循环每次往里面加一条直线&#xff0c;计算交点 #include <iostream>…

Ubuntu Desktop - Updates (不升级到新版本)

Ubuntu Desktop - Updates [不升级到新版本] 1. UpdatesReferences 1. Updates System Settings -> Software & Updates -> Updates ubuntu-16.04.3-desktop-amd64.iso 不升级到新版本 ​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

TypeScript 常见的面试题

文章目录 1. 什么是TypeScript2. 类型声明和类型推断的区别&#xff0c;并举例应用3. 什么是接口&#xff08;interface&#xff09;&#xff0c;它的作用&#xff0c;接口的使用场景。接口和类型别名&#xff08;Type Alias&#xff09;的区别4. 什么是泛型&#xff08;generi…

RK3588开发笔记-v1.3.0-SDK文件系统分区添加

目录 目录 前言 一、分区文件 二、分区文件初始化 三、板级配置文件修改

【Linux】nmcli命令详解

目录 ​编辑 一、概述 二、常用参数使用 2.1 nmcli networking 1.显示NM是否接管网络 2.查看网络连接状态 3.开/关网络连接 2.2 general ​编辑 1.显示系统网络状态 2.显示主机名 3.更改主机名 2.3 nmcli connection ​编辑1.显示所有网络连接 2.显示某个网卡的…

JAVA 100道题(15)

15.使用TreeSet对一组整数进行排序。 在Java中&#xff0c;TreeSet是一个基于红黑树实现的NavigableSet接口。由于它是自动排序的&#xff0c;因此当我们向TreeSet中添加元素时&#xff0c;它们会自动按照自然顺序&#xff08;对于整数&#xff0c;就是从小到大的顺序&#xf…

【数据结构】快速排序(用递归)

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解快速排序&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 基本思想二. 快速排序2.1 hoare版本2.2 挖坑法2.3 前后指针法2.4 快速排序优化三数取中法…

redis 基本操作

1、String 类型 赋值语法&#xff1a;SET key value 127.0.0.1:6379> set k1 zhangsan OK 取值语法&#xff1a; GET key 127.0.0.1:6379> get k1 "zhangsan" 设置多个键语法&#xff1a; MSET key value [key value …] 127.0.0.1:6379> mset k2 lisi k3 …

Python学习目录

基础篇 变量赋值篇字符串(string)篇&#xff08;一&#xff09;字符串(string)篇&#xff08;二&#xff09;字符串(string)篇&#xff08;三&#xff09;字符串(string)篇&#xff08;四&#xff09;字符串(string)篇&#xff08;五&#xff09;列表(list)篇&#xff08;一&a…

【Android】【Bluetooth Stack】蓝牙电话协议之接听电话分析(超详细)

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待&#xff0…

MySQL详解

本笔记源于【狂神说Java】 B站收UP主&#xff1a;遇见狂神说。即可看见教程 或者点击链接MySQL最新教程 目录 1、初始MySQL 1.1、数据库简介 1.2、数据库管理系统 1.3、MySQL简介及安装 1.4、SQLyog 2、操作数据库 2.1、操作数据库&#xff08;了解&#xff09; 2.2、数…

LangChain核心模块 Retrieval——Indexing

Indexing 索引 LangChain Indexing API将数据从任何来源同步到向量存储中并保持同步&#xff0c;可以做到&#xff1a; 避免将重复内容写入矢量库避免重写未更改的内容避免在未更改的内容上重新计算嵌入 最重要的是&#xff0c;Indexing API 甚至可以处理相对于原始源文档经…