C++基础:muduo库学习记录

news/2024/12/2 14:09:07/

2024/11/26-2024/11/2 :
  记录一下在自己学习muduo库时对一些概念的理解和实现。
reference:
[1]C++Muduo网络库:简介及使用
[2]Linux-C网络编程之epoll函数
[3]Linux平台下muduo网络库源码编译安装

目录

  • 一、基础概念
    • 1.1 阻塞 or 非阻塞 同步 or 异步
    • 1.2 IO模型
  • 二、muduo库的简单使用
    • 2.1muduo 网络库简述

一、基础概念

1.1 阻塞 or 非阻塞 同步 or 异步

从IO角度来看这几个概念,可以从recv这个函数入手。

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

详细的参数介绍就此略过。总之,recv函数或者说几乎所有IO系统调用做的事情我们可以将其分为两个阶段,一个是数据准备,一个是进行数据读写

Created with Raphaël 2.3.0 recv开始 数据准备:查看接收缓冲区是否有数据 数据读写:将接收缓冲区的数据拷贝到指定位置 recv结束

阻塞和非阻塞在数据准备状态起作用,表现出的状态是阻塞当前线程 or 直接返回;
而同步和异步则决定着数据读写的方式,在同步中,数据的读写由执行指令的线程本身从头到尾完成,耗费的是当前线程的执行时间,而异步意味着将数据的读写交给其他线程处理,自己去执行其他命令,不增加本线程的执行时间,并与线程进行完成任务后通信方式的约定。可以类比一下DMA技术的思想。
两两组合便有4种:

  • 同步阻塞(blocking IO 模型)
    数据准备阶段查看接收缓冲区,无数据或者数据没发完则阻塞等待,数据发完则接收数据并返回,数据读写由本进程执行。
  • 同步非阻塞(non-blocking IO 模型)
    recv工作在非阻塞状态下时,不管缓冲区是否有数据、数据是否完整都会立即返回,通过返回值来判断是否拿到数据,通常需要轮询执行。数据读写由本进程执行。
  • 异步阻塞
    将事务递交给操作系统或者其他线程完成,自己也同时阻塞等待完成信号。没有存在的必要,效率过低,只有理论上存在这种模型。
  • 异步非阻塞(异步模型)
    线程将读写缓冲区的事务操作系统或者其他线程来操作,自己去执行别的任务,执行任务者使用信号或者回调函数通知进程传输完成,注意通知的方式需要提前约定。这种IO方式效率较高,需要操作系统给予支持,实现真正意义上的异步,可以将数据准备和读写操作都由另外的线程完成。但是,这种方式的编程比较复杂,出错调试也最麻烦。

1.2 IO模型

除了上面四种组合方式包括的三种IO模型,另有两种IO模型:

  • IO 复用模型
    IO复用模型中,进程在select/poll/epoll等函数处阻塞并等待返回可读套接字,之后根据返回套接字的不同自己进行数据的读写,因此这同样也是一种同步的模型,通常需要轮询执行。至于该模型的数据准备阶段是否阻塞,则取决于函数的具体参数和设置,但通常使用非阻塞方式。之后的数据读写同步阻塞。
  • 信号驱动模型
    应用进程注册信号处理程序,立即得到返回的信号状态后进程继续执行,直到得到数据处理完成的信号——这是一个异步的过程,而信号通知机制避免了轮询查询操作,提高了效率。

注意信号驱动和IO 复用只是在数据准备阶段有所区别,之后的数据读写系统调用依然是一个同步阻塞的过程。
信号驱动跟异步模型的区别是,信号驱动在数据准备阶段结束时便返回信号,让主进程自己进行数据读写,而异步模型在数据读写后返回信号。

二、muduo库的简单使用

2.1muduo 网络库简述

muduo 网络库为用户提供了两个主要的类:

  • TcpServer:用于编写服务器程序。
  • TcpClient:用于编写客户端程序。

muduo 基于 epoll 事件驱动模型,并结合线程池机制,能够高效地处理网络 I/O 操作。epoll + 线程池的优势使其能够把线程池IO的代码和业务代码区分开,让我们可以只负责编写连接和断开和用户的读写事件相关的函数(即下文setConnectionCallbacksetMessageCallback函数)。

muduo的使用则比较模板化,如上所说,我们只需要关注网络连接的处理(相当于处理epoll中的listenfd事件)以及业务处理相关代码,具体如下:

/** 基于muduo网络库开发服务器程序* 1.组合TcpServer对象* 2.创建EventLoop事件循环对象的指针* 3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数* 4.在当前服务器类的构造函数中,注册处理连接的回调函数和处理IO事件的回调函数* 5.设置合适的服务端线程数量,muduo库会自己分配IO线程和worker线程*/// 基于事件驱动的IO复用服务器
class ChatServer {
public:ChatServer(EventLoop* loop,                 // 事件循环const InetAddress& listenAddr,   // IP + portconst string& nameArg)           // 服务器的名字:_server(loop, listenAddr, nameArg),_loop(loop) {// 给服务器注册用户连接的创建和断开回调_server.setConnectionCallback(bind(&ChatServer::onConnection, this, _1));// 给服务器注册用户读写事件回调_server.setMessageCallback(bind(&ChatServer::onMessage, this, _1, _2, _3));// 设置服务器端的线程数量  muduo库自动分配:1个IO线程  4个worker线程_server.setThreadNum(5);}// 开启事件循环void start() {_server.start();}
private:// 专门处理用户连接的创建和断开epoll listen 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();   // 退出epoll}}void onMessage(const TcpConnectionPtr &conn,    // 连接Buffer *buffer,                  // 缓冲区Timestamp time) {                // 接收到数据的时间信息string buf = buffer->retrieveAllAsString();cout << "recv data: " << buf << " time: " << time.toString() << endl;conn->send(buf);// 可以根据用户发送的buffer中的信息来定制不同的业务处理}TcpServer _server;  // #1EventLoop *_loop;   // #2 epoll
};int main() {EventLoop loop; // epollInetAddress addr("127.0.0.1", 6000);ChatServer server(&loop, addr, "ChatServer");server.start(); // listen 和 epoll_ctl 添加到 epoll上loop.loop();    // epoll_wait——以阻塞方式等待新用户连接,已连接用户的读写事件等return 0;
}

可以看到muduo基本上帮我们处理完了关于连接和接收数据的操作,我们只需要根据用户发送的信息进行不同的业务处理即可。


http://www.ppmy.cn/news/1551776.html

相关文章

pgsql指令

linux 在安装pgsql的服务器上 root是用户名&#xff0c;test是数据库名 psql -U root -d test登录后显示&#xff0c;12,6是版本号 psql (12.6) 查询所有表 \dt查询表结构 \d table_name查询表所属 \dp manual_logistics_logSELECT n.nspname AS table_schema,c.relname …

Spring Security6 OAuth2 实现流程

一 通用的权限框架需求 1 响应数据格式需要统一 示例 { "code": "success", "message": "description", "data": null } ps:code: 状态码&#xff0c;后台定义给前端用&#xff0c;比如“token.expired”&#xff0c;前…

AJAX一、axios使用,url组成(协议,域名,资源路径)查询参数和化简,错误处理,请求/响应报文,状态码,接口文档,

一、AJAX是什么 概念 &#xff1a; AJAX是一种与服务器&#xff08;后端&#xff09;通信的技术 二、请求库axios的基本用法 1导包 2使用 // 1. 发请求 axios({ url: 请求地址 }).then(res > { // 2.接收并使用数据 }) <body><p class"province"…

游戏引擎学习第26天

编程实际游戏的第一天 在第一天的编程中&#xff0c;目标是开始编写游戏的实际部分。虽然之前有一个原型层已经完成&#xff0c;但目前这个层次只是为了快速开发和验证游戏的基本功能&#xff0c;并不适合直接发布给终端用户。虽然这个原型层足够让游戏开发顺利进行&#xff0…

学习threejs,使用CubeCamera相机创建反光效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️CubeCamera 立方体相机 二、…

具有多个表盘、心率传感器、指南针和游戏的 DIY 智能手表

在此&#xff0c;我们将使用所学到的知识&#xff0c;结合使用硬件和软件组件从头开始创建自己的智能手表。在项目的这一部分&#xff0c;您将被指导完成组装硬件组件、设置软件以及配置智能手表的设置和功能的过程。到本项目结束时&#xff0c;您将拥有一款功能齐全的智能手表…

win32com python 操作wps 解决修改 表格触发关闭 其他excel的功能

win32com python 操作wps 是很方便的一个东西 之前唯一的缺点就是会关闭wps的表格。 解决思路 新开wps 进程来处理 import os import subprocess import win32com.client as win32 import timedata [] def get_col_value(sheet):# 参数设置row_index 2 # 第二行start_colum…

记一次搞校园网的经历

接教室的校园网&#xff0c;到另一个屋子玩电脑&#xff0c;隔墙想放大一下AP的信号&#xff0c;发现死活不行 这是现状 由于校园网认证的存在&#xff0c;无法用桥接&#xff0c;桥接需要路由器有IP&#xff0c;而这个IP无法用未刷机的路由器来打开校园网页面认证 解决 将一…