首页 > 其他分享 >详解Muduo库

详解Muduo库

时间:2024-07-01 22:29:54浏览次数:3  
标签:muduo 详解 server Muduo 线程 事件 服务器 loop

一、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 + ]),连接断开,可以看到服务器也能够正常退出。

标签:muduo,详解,server,Muduo,线程,事件,服务器,loop
From: https://blog.csdn.net/m0_71124168/article/details/140111518

相关文章

  • Apipost接口测试工具的原理及应用详解(四)
    本系列文章简介:        随着软件行业的快速发展,API(应用程序编程接口)作为不同软件组件之间通信的桥梁,其重要性日益凸显。API的质量直接关系到软件系统的稳定性、性能和用户体验。因此,对API进行严格的测试成为软件开发过程中不可或缺的一环。在众多API测试工具中,Apipost......
  • Apipost接口测试工具的原理及应用详解(五)
    本系列文章简介:        随着软件行业的快速发展,API(应用程序编程接口)作为不同软件组件之间通信的桥梁,其重要性日益凸显。API的质量直接关系到软件系统的稳定性、性能和用户体验。因此,对API进行严格的测试成为软件开发过程中不可或缺的一环。在众多API测试工具中,Apipost......
  • Appium+python自动化(三十三)- 本地调试测试代码,远程控制测试环境-Remote(超详解)
    简介在前边所有涉及启动app的时候有这样一行代码driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps),很多小伙伴们和同学们不知道这个ip和端口哪里来的,我觉得有必要给小伙伴解释一下,于是宏哥决定写一篇关于这个appium的服务器ip文章!来给大家答答疑......
  • C/C++ Dijkstra(迪杰斯特拉)算法详解及源码
    Dijkstra(迪杰斯特拉)算法是一种用于寻找带权重图中的最短路径的算法。它由荷兰计算机科学家EdsgerDijkstra于1956年提出,被广泛应用于网络路由算法和地图路线规划等领域。算法思想:初始化一个距离数组,用于保存起点到每个顶点的当前最短距离(初始时将起点距离设置为0,其他顶......
  • SQL Server的守护神:Always On 高可用性详解
    ......
  • Spring的AOP概念详解
    AOP详解:1.介绍:面向切面编程,是一种将非业务代码与业务代码进行分离的一种思想,在实际开发中,往往有许多重复操作,例如事务提交,权限验证,保存口志等功能需要在业务代码重复调用,面向切面编程,就是将非业务代码进行抽取,然后在不修改原来代码的前提下,为我们的业务代码,添加额......
  • 鸿蒙技术之WebSocket连接详解
    WebSocket连接详解WebSocket是一种在单个TCP连接上提供全双工通信信道的协议,它允许服务器主动向客户端推送数据,非常适合实时通信和数据交换频繁的应用场景。以下是WebSocket连接的详细步骤和知识点:1.创建WebSocket对象首先,需要通过createWebSocket()方法创建一个WebSock......
  • 【Linux命令详解 - ssh命令】 ssh命令用于远程登录到其他计算机,实现安全的远程管理
    文章标题简介一,参数列表二,使用介绍*1\.连接远程服务器2.使用SSH密钥登录*2.1生成密钥对2.2将公钥复制到远程服务器3.端口转发*3.1本地端口转发3.2远程端口转发4.X11转发5.文件传输与远程命令执行*5.1文件传输*5.1.1从本地向远程......
  • 使用Swagger 3注解编写API文档详解
    在现代软件开发中,API文档的编写是至关重要的一环,它不仅能帮助开发者理解和正确使用API,还能提升团队协作效率。Swagger3是一个流行的API文档规范,通过注解的方式可以清晰地定义API的各个方面。本文将深入探讨Swagger3中常用的注解及其使用方法。@OpenAPIDefinition和@Inf......
  • Spring Boot 全局异常捕获机制详解
    在SpringBoot中,全局异常捕获机制是处理RESTHTTP请求时的一个重要功能,它可以确保所有未被捕获的异常都能被统一处理。本文将深入探讨SpringBoot中全局异常捕获的实现,从请求进入到异常处理的全过程。请求处理流程概述请求进入DispatcherServlet:所有HTTP请求首先到达......