muduo库的初步认识和基本使用,创建一个简单查询单词服务系统

news2025/7/21 5:45:21

小编在学习完muduo库之后,觉得对于初学者,muduo库还是有点不好理解,所以在此,小编来告诉大家muduo库的初步认识和基本使用,让初学者也可以更快的上手和使用muduo库

Muduo由陈硕大佬开发,是⼀个基于 非阻塞IO和事件驱动的C++高并发TCP网络编程库 。 它是⼀款基
于主从Reactor模型的网络库,其使用的线程模型是one loop per thread, 所谓one loop per thread
指的是:
        a. ⼀个线程只能有⼀个事件循环(EventLoop), 用于响应计时器和IO事件
        b.⼀个文件描述符只能由⼀个线程进行读写,换句话说就是⼀个TCP连接必须归属于某个EventLoop管理。

一、muduo的初步认识

1、对TcpServer.h的初步认识

这张图片告诉大家muduo库的构造函数,让我来解释一下没给参数的概念及意思。

        a.EventLoop* loop 是TcpServer的事件循环监控,它是一个死循环,大家知道多路转接的时候需要一个事件循环监控,来告诉我们那个事件已经就绪,然后我们来进行对这个事件的操作,所以这个loop就是来做这个事情的,后面我们会介绍这个 loop的头文件,不着急。

        b.const InetAddress& listenAddr 储存的是TcpServer监听的ip地址和端口号,TcpServer要进行启动,必须有一个可以被外部连接的ip和端口号才可以。

        c.const string& nameArg 是你这个TcpServer服务的名字,这个就是自己对自己的服务起一个名字。

        d.Option option = kNoReusePort 是一个选项,告诉操作系统是否要开启地址复用,他的选项 第一个KNoReusePort是不开启地址复用,第二个KReusePort是开启地址复用。

2、对TcpServer.h中其他重要函数的认识

这个函数是TcpServer.h中必须要进行设置的函数,这个函数的意思是我们接收到外部的连接后需要调用的回调函数,可能到这里大家还不知道有啥用,先不着急,继续往后看。

这个函数也是TcpServer.h中必须要设置的函数,这个函数的意思是我们进行事件监控之后,收到外部发来的消息需要对消息进行的处理回调函数,也是继续往后看。

这个函数是开启TcpServer服务

3、对EventLoop.h的认识

构造函数没有参数,直接无参构造就好。

这个函数来直接启动事件循环操作,内部是一个死循环

4、对TcpClient.h的认识

还是一样,让我来告诉大家这个TcpClient的构造函数的参数意思。

        a.EventLoop* loop 和TcpServer构造函数中的意思一样,但是有个不一样的地方是在TcpClient中不能让TcpClient是一个死循环,因为EventLoop是一个死循环,因为客户端要进行对服务端发送消息,不能让事件循环监控是一个死循环这样客户端就不能往下执行了,只能一直对事件进行循环监控,后面使用一下大家也就会了。

        b. const InetAddress& serverAddr 的意思客户端要访问的服务端的ip和端口号。

        c.const string& nameArg 的意思和服务端的意思一样,也就是给客户端起一个名字。

5、对TcpClient.h中重要的函数的认识

这个函数的意思是对客户端连接服务端之后调用的回调函数,这个函数也必须要设置

这个函数的意思是客户端进行事件监控之后,收到消息之后,调用的对消息处理的回调函数,也必须要设置

这个函数的意思是对服务端进行连接,连接之后直接自己启动客户端的操作。

6、对TcpConnection.h的认识

这个类比较特别,不需要我们对它进行手动设置参数,它是我们客户端连接到服务端之后,服务端和客户端会创建一个TcpConnection来保存客户端和服务端的信息,包括客户端和服务端的端口号和ip地址,为两端进行通信创建条件。

这个send的接口就是我们进行通信的基础,虽然这个函数有三个重载函数,但是他们的效果都是一样的,都是向对方发送信息报文

这两个接口告诉我们两端是否连接成功,connected接口告诉我们两端是否连接正常,disconnected反之

7、对Buffer.h的认识

这个类也就是muduo库自己设置的缓冲区,方便我们对双方的消息进行处理和保存的类,这个类也不需要我们自己进行设置,他自己会进行设置,所以这里的构造函数的参数不需要我们自己管理,在这里我也就不说啦。

8、对Buffer.h中重要函数的认识

这些函数接口都是对Buffer缓冲区进行的读取数据的操作retrieve接口虽然有很多,但是他们的操作方式都一样,这里咱们以个别为例,retrieveInt64() 这个接口要读取64字节的数据,并且读取完成之后,会把这64字节的数据清空,很好理解,就是读取走缓冲区中的数据,其他的也都一样。还有retrieveAllAsString() 这个接口是用来读取Buffer缓冲区中的所有数据并把它当作一个字符串,也很好理解吧。其他的也都类似,这里就不做讲解了。

9、对EventLoopThread.h的认识

这个类和EventLoop的类功能相似,都是对事件进行循环监控,但是这个类是用开辟一个线程帮我们进行循环监控,这样我们主线程就可以做自己想做的事情了,也就是我们客户端需要用到的这个事件循环监控,因为客户端不可以被阻塞到事件循环监控那块。这个构造函数里面的参数也不用我们用户自己传,所以在这里我也不再讲解。

10、对EventLoopThread.h中重要函数的理解

这个函数来告诉我们它的EventLoop的指针,因为它的底层也是事件循环监控EventLoop。

11、对CountDownLatch.h的认识

这个类协助我们对客户端正确性进行维护,因为客户端在进行连接之后就会自动开始对服务端发送报文,但是如果客户端没有连接到服务端就对服务端发送消息,这不就出错了吗,所以在这里才有了这个类,这个构造函数传的count就是一个数字,当这个数字减为0就唤醒阻塞,如果这个数字大于0就一直阻塞住,不让客户端发送消息给服务端,可能有点不理解,后面看例子一下子就明白。

12、对CountDownLatch.h中重要函数的理解

这个wait函数一直进行阻塞countDown函数每次调用就对构造函数中的count进行-1操作,直到减为0,就唤醒wait操作,还是和上面一样,一看例子就明白。

二、基本使用muduo库,创建一个简单的单词查询系统

1、首先我们先看服务端的实现及其代码和注释来理解

class dictServer
{
public:
    dictServer()
        :_dictserver(&_loop, muduo::net::InetAddress("0.0.0.0", 9090),
                        "dictserver", muduo::net::TcpServer::Option::kReusePort)  // 最后一个参数的意思是是否开启地址复用
    {
        // 设置这几个必须要的函数
        _dictserver.setConnectionCallback(std::bind(&dictServer::connectionCallBack, this, std::placeholders::_1));
        _dictserver.setMessageCallback(std::bind(&dictServer::messageCallBack, this, 
            std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
        // 给字典插入数据 随便插入几个单词进行test实验
        _dictmap["hello"] = "你好";
        _dictmap["world"] = "世界";
        _dictmap["apple"] = "苹果";
    }
    void running()
    {
        // 启动tcp服务和事件循环监控loop服务
        _dictserver.start();
        _loop.loop();
    }
    ~dictServer(){}
private:
    void connectionCallBack(const muduo::net::TcpConnectionPtr& conn)
    {
        // 判断是否连接成功
        if(conn->connected())
        {
            std::cout << "连接成功!" << std::endl;
        }
        else
        {
            std::cout << "连接失败!" << std::endl;
        }
    }
    void messageCallBack(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp time)
    {
        // 取出来buf里面的数据 进行查询 因为我们没有定制其他协议 这里如果收到客户端发来的一个单词直接全部取出来进行操作
        std::string str = buf->retrieveAllAsString();
        // 对这个单词进行查询
        auto it = _dictmap.find(str);
        std::string msg;
        if(it != _dictmap.end())
        {
            // 找到了数据
            msg = (*it).second;
        }
        else
        {
            msg = "None";
        }
        // 把查询到的数据发送给客户端
        conn->send(msg);
    }
private:
    // 因为需要现有 eventloop对象才可以初始化tcpserver对象 所以eventloop对象应在tcpserver上面 这样初始化列表才会正确
    muduo::net::EventLoop _loop;
    muduo::net::TcpServer _dictserver;
    std::unordered_map<std::string, std::string> _dictmap;
};


int main()
{
    dictServer dict;
    // 启动服务端
    dict.running();


    return 0;
}

2、我们来看客户端的实现及其代码和注释来理解

class dictclient
{
public:
    dictclient()
        // 这里直接获取EventThreadLoop的指针给EventLoop对象
        :_loop(_loopthread.startLoop())     // loophtread 开始创建了对象之后 就可以自己在线程中自己循环监控数据
        , _client(_loop, muduo::net::InetAddress("127.0.0.1", 9090), "dictclient")
        ,_downlatch(1)   // 这里的count我们设置为一, 如果连接上就给count--,直接唤醒wait操作,让客户端来进行通信
    {
        // 设置这两个必须设置的函数对象
        _client.setConnectionCallback(std::bind(&dictclient::connCallBack, this, std::placeholders::_1));
        _client.setMessageCallback(std::bind(&dictclient::mesCallBack, this, std::placeholders::_1, 
            std::placeholders::_2, std::placeholders::_3));
        _client.connect();  // 这里只是发起了客户端连接服务端的操作
        _downlatch.wait();  // 用CountDownLatch的类来对客户端进行保护阻塞操作
    }

    bool send(const std::string& mes)
    {
        if(_conn->connected())
        {
            // 连接建立成功 可以发送消息
            _conn->send(mes);
            return true;
        }

        return false;
    }

    ~dictclient() {}
private:
    void connCallBack(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            std::cout << "连接成功!" << std::endl;
            _conn = conn;     // 把这个conn给到自己
            _downlatch.countDown();  // 让计数器减减 唤醒阻塞client
        }
        else
        {
            std::cout << "连接失败!" << std::endl;
            _conn.reset();   // 释放这个指针指向的空间
        }
    }

    void mesCallBack(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp timestamp)
    {
        // 取出来buf里面的数据 进行查询
        std::string str = buf->retrieveAllAsString();
        std::cout << str << std::endl;
    }

private:    
    muduo::net::TcpConnectionPtr _conn;  // 因为客户端无法自己访问连接完毕之后创建的TcpConnection对象,所以在此我们进行手动设置一个这个对象
    muduo::CountDownLatch _downlatch;
    muduo::net::EventLoopThread _loopthread;
    muduo::net::EventLoop* _loop;
    muduo::net::TcpClient _client;
};

int main()
{
    dictclient client;
    while(true)
    {
        std::string mes;
        std::cin >> mes;
        client.send(mes);
    }
    return 0;
}

以上就是我们今天学习的所有内容,如果有什么不理解的地方,大家可以评论区留言或者私信我,我给大家答疑!下期再见啦!

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

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

相关文章

【HTML/CSS面经】

HTML/CSS面经 HTML1. script标签中的async和defer的区别2. H5新特性&#xff08;1 标签语义化&#xff08;2 表单功能增强&#xff08;3 音频和视频标签&#xff08;4 canvas和svg绘画&#xff08;5 地理位置获取&#xff08;6 元素拖动API&#xff08;7 Web Worker&#xff08…

git查看commit属于那个tag

1. 快速确认commit原始分支及合入tag # git describe 213b4b3bbef2771f7a1b8166f6e6989442ca67c8 查看commit合入tag # git describe 213b4b3bbef2771f7a1b8166f6e6989442ca67c8 --all 查看commit原始分支 2.查看分支与master关系 # git show --all 0.5.67_0006 --stat 以缩…

mysql-mysql源码本地调试

前言 先进行mysql源码本地编译&#xff1a;mysql源码本地编译 1.本地调试 这里以macbook为例 1.使用vscode打开mysql源码 2.创建basedir目录、数据目录、配置文件目录、配置文件 cd /Users/test/ mkdir mysqldir //创建数据目录和配置目录 cd mysqldir mkdir conf data …

PCIe— Legacy PCI

Legacy Model ​​ 该器件通过将其引脚置位到控制器来生成中断。 在较旧的系统中&#xff0c;这个控制 器通常是Intel 8259 PIC&#xff0c;有15个IRQ输入和一个INTR输出。 然后&#xff0c;PIC将断 言INTR以通知CPU一个或多个中断正在挂起。 一旦CPU检测到INTR的断言…

PostgreSQL数据库配置SSL操作说明书

背景&#xff1a; 因为postgresql或者mysql目前通过docker安装&#xff0c;只需要输入主机IP、用户名、密码即可访问成功&#xff0c;这样其实是不安全的&#xff0c;可能会通过一些手段获取到用户名密码导致数据被窃取。而ES、kafka等也是通过用户名/密码方式连接&#xff0c;…

低碳理念在道路工程中的应用-预制路面

一、引子 在上一篇文章里&#xff0c;给大家介绍了预制基层的应用&#xff0c;有人提出&#xff0c;既然基层能够预制&#xff0c;那么&#xff0c;道路面层能不能预制呢&#xff0c;有没有相关的研究成果和应用实例呢&#xff1f;答案是肯定的&#xff0c;在本篇文章中&#x…

12-后端Web实战(登录认证)

在前面的课程中&#xff0c;我们已经实现了部门管理、员工管理的基本功能&#xff0c;但是大家会发现&#xff0c;我们并没有登录&#xff0c;就直接访问到了Tlias智能学习辅助系统的后台。 这是不安全的&#xff0c;所以我们今天的主题就是登录认证。最终要实现的效果是&#…

4.2.2 Spark SQL 默认数据源

在本实战概述中&#xff0c;我们探讨了如何在 Spark SQL 中使用 Parquet 格式作为默认数据源。首先&#xff0c;我们了解了 Parquet 文件的存储特性&#xff0c;包括其二进制存储方式和内嵌的 Schema 信息。接着&#xff0c;通过一系列命令&#xff0c;我们演示了如何在 HDFS 上…

234. Palindrome Linked List

目录 一、题目描述 方法一、使用栈 方法二、将链表全部结点值复制到数组&#xff0c;再用双指针法 方法三、递归法逆序遍历链表 方法四、快慢指针反转链表 一、题目描述 234. Palindrome Linked List 方法一、使用栈 需要遍历两次。时间复杂度O(n)&#xff0c;空间复杂度…

无人机报警器探测模块技术解析!

一、运行方式 1. 频谱监测与信号识别 全频段扫描&#xff1a;模块实时扫描900MHz、1.5GHz、2.4GHz、5.8GHz等无人机常用频段&#xff0c;覆盖遥控、图传及GPS导航信号。 多路分集技术&#xff1a;采用多传感器阵列&#xff0c;通过信号加权合并提升信噪比&#xff0c;…

Bonjour

Bonjour 是苹果的一套零配置网络协议&#xff0c;用于发现局域网内的其他设备并进行通信&#xff0c;比如发现打印机、手机、电视等。 一句话&#xff1a;发现局域网其他设备和让其他设备发现。 Bonjour 可以完成的工作 IP 获取名称解析搜索服务 实际应用场景示例&#xff0…

华为云Flexus+DeepSeek征文 | 基于Dify和DeepSeek-R1开发企业级AI Agent全流程指南

作者简介 我是摘星&#xff0c;一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型&#xff0c;将实际使用经验分享给大家&#xff0c;希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 1. 前言 2. 环境准备 2.1 华为云资源准备 2.1 实…

HarmonyOS-ArkUI固定样式弹窗(1)

固定样式弹窗指的就是ArkUI中为我们提供的一些具备界面模板性质的弹窗。样式是固定的,我们可以决定在这些模板里输入什么样的内容。常见的有,警告弹窗, 列表选择弹窗, 选择器弹窗,对话框,操作菜单。 下图是本文中要讲到的基类固定样式弹窗,其中选择器弹窗没有包含在内,…

痉挛性斜颈相关内容说明

一、颈部姿态的异常偏移​ 痉挛性斜颈会打破颈部原本自然笔直的状态&#xff0c;让颈部像被无形的力量牵引&#xff0c;出现不自主的歪斜、扭转。它就像打乱了颈部原本和谐的 “平衡游戏”&#xff0c;使得颈部姿态偏离正常&#xff0c;影响日常的体态与活动。​ 二、容易察觉…

【25-cv-05917】HSP律所代理Le Petit Prince 小王子商标维权案

Le Petit Prince 小王子 案件号&#xff1a;25-cv-05917 立案时间&#xff1a;2025年5月28日 原告&#xff1a;SOCIETE POUR LOEUVRE ET LA MEMOIRE DANTOINE DE SAINT EXUPERY - SUCCESSION DE SAINT EXUPERY-DAGAY 代理律所&#xff1a;HSP 原告介绍 《小王子》&#x…

vue3 ElMessage提示语换行渲染

在 ElMessage.error 中使用换行符 \n 并不会实现换行&#xff0c;因为 ElMessage 默认会将字符串中的换行符忽略。要实现换行显示&#xff0c;可以使用 HTML 标签 <br> 并结合 ElMessage 的 dangerouslyUseHTMLString 选项。以下是实现换行提示的代码示例&#xff1a; i…

Java 微服务架构设计:服务拆分与服务发现的策略

Java 微服务架构设计&#xff1a;服务拆分与服务发现的策略 微服务架构作为一种热门的软件架构风格&#xff0c;在 Java 领域有着广泛的应用。它通过将系统拆分为一组小型服务来实现更灵活、可扩展的系统设计。在微服务架构中&#xff0c;服务拆分和服务发现是两个关键环节。本…

华为OD机试真题——二叉树中序遍历(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《二叉树中序遍历》: 目录 …

VSCode + GD32F407 构建烧录

前言 最近调试一块 GD32F407VET6&#xff08;168Mhz&#xff0c;8Mhz晶振&#xff09; 板子时&#xff0c;踩了一些“启动失败”的坑。本以为是时钟配置有误&#xff0c;最后发现是链接脚本&#xff08;.ld 文件&#xff09;没有配置好&#xff0c;导致程序根本没能正常执行 ma…

Linux研学-入门命令

一 目录介绍 1 介绍 Linux与Windows在目录结构组织上差异显著&#xff1a;Linux采用树型目录结构&#xff0c;以单一根目录/为起点&#xff0c;所有文件和子目录由此向下延伸形成层级体系&#xff0c;功能明确的目录各司其职&#xff0c;使文件系统层次清晰、逻辑连贯&#xf…