[集群聊天项目] muduo网络库

news2025/1/11 20:00:00

目录

  • 网络服务器编程常用模型
  • 什么是muduo网络库
    • 什么是epoll
  • muduo网络库服务器编程

网络服务器编程常用模型

【方案1】 : accept + read/write
不是并发服务器

【方案2】 : accept + fork - process-pre-connection
适合并发连接数不大,计算任务工作量大于fork的开销

【方案3】 :accept + thread thread-pre-connection
比方案2的开销小了一点,但是并发造成线程堆积过多

【方案4】: muduo的网络设计:reactors in threads - one loop per thread

【方案5】 : reactors in process - one loop pre process
nginx服务器的网络模块设计,基于进程设计,采用多个Reactors充当I/O进程和工作进程,通过一把accept锁,完美解决多个Reactors的“惊群现象”

什么是muduo网络库

高并发,因此服务器要用muduo编程
在这里插入图片描述
在这里插入图片描述

方案的特点是one loop per thread(一个线程一个时间循环),有一个main reactor负载accept连接(I/O线程),然后把连接分发到某个sub reactor(采用round-robin[轮询]的方式来选择sub reactor),该连接的所用操作都在那个sub reactor所处的线程中完成,注册到某个线程的epoll事件上,那么所做的所有读写操作都在这个epoll上完成。多个连接可能被分派到多个线程中,以充分利用CPU。

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

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

// 设置EventLoop的线程个数,底层通过EventLoopThreadPool线程池管理线程类EventLoopThread
_server.setThreadNum(10);

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

什么是epoll

学习资料
epoll 是 Linux 内核的可扩展 I/O 事件通知机制,其最大的特点就是性能优异。
在这里插入图片描述

muduo网络库服务器编程

moduo库的使用需要链接libmuduo_base.solibmuduo_net.solibpthread.so库,我们执行的时候需要-lmuduo_net -lmuduo_base -lpthread,需要配置这些。

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

  • TcpSever : 用于编写服务器程序的
  • TcpClient : 用于编写客户端程序的

eopll + 线程池
好处:能把网络I/O的代码和业务代码区分开

业务代码的暴露主要有两个:用户的连接和断开,用户的可读写事件。我们只需要关注这两个事件怎么做,至于什么时候发生这些事情(网络库上报)以及怎么监听这些事件的发生,都是由网络库实现好的。

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

1. 组合TcpSevrer对象:不指定构造TcpServer _server;就要用默认构造,但是进入到TcpServer.h中发现TcpServer没有默认构造,因此要指定_server相应的构造,在pubilc中。不指定,ChatServer类无法创建对象。
TcpServer没有默认构造

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

TcpServer _server; // #1
EventLoop *_loop;  // #2 epoll

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

ChatServer(EventLoop *loop,               // 事件循环
       const InetAddress &listenAddr, // IP地址+端口
           const string &nameArg)         // 服务器的名字
    : _server(loop, listenAddr, nameArg), _loop(loop)
{}

4.在当前服务器类的构造函数中,注册处理连接的回调函数和处理读写事件的回调函数。将处理业务的代码onConnectiononMessage分离出来,和对应的Callback代码绑定到一起,其中onConnectiononMessage两个函数的参数类型和数量是根据Callback函数设置的。
在这里插入图片描述

// 给服务器注册用户连接的创建和断开回调,一旦监听到此活动,就会调用onConnection函数
// 人家的Callback函数只有一个参数,但是自己写的onConnection有两个参数,隐含一个this
// _1是参数占位符(需要using namespace placeholders;),是onConnection括号中的参数
_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));
// 给服务器注册用户读写事件回调
_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));
// **************************************************************
// 专门处理用户的连接创建和断开 epoll  listenfd accept
void onConnection(const TcpConnectionPtr &conn)
{// 放业务代码}

// 专门处理用户的读写事件
void onMessage(const TcpConnectionPtr &conn, // 连接
               Buffer *buffer,               // 缓冲区
               Timestamp time)               // 接收到数据的时间信息
{// 放业务代码}

5. 设置合适的服务端线程数,muduo库会自己分配I/O线程和worker线程

// 设置服务器端的线程数量 1个I/O线程 3个worker线程
_server.setThreadNum(4);

全部代码:

#include <muduo/net/TcpServer.h>
#include <muduo/net/TcpClient.h>
#include <iostream>
#include <functional> //绑定器在此文件中
#include <string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;

class ChatServer
{
public:
    // #3
    ChatServer(EventLoop *loop,
               const InetAddress &listenAddr,
               const string &nameArg)
        : _server(loop, listenAddr, nameArg), _loop(loop)
    {
        // #4
        _server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));
        _server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));

        // #5
        _server.setThreadNum(4);
    }

    // 开启事件循环
    void start()
    {
        _server.start();
    }

private:
    // 专门处理用户的连接创建和断开 epoll  listenfd accept
    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(); // close(fd)
            // _loop->quit();
        }
    }

    // 专门处理用户的读写事件
    void onMessage(const TcpConnectionPtr &conn,
                   Buffer *buffer,
                   Timestamp time)
    {
        // 放业务代码
        string buff = buffer->retrieveAllAsString();
        cout << "recv data:" << buff << "time: " << time.toString() << endl;
        conn->send(buff);
    }

    TcpServer _server;
    EventLoop *_loop;
};

int main()
{
    EventLoop loop; // epoll
    InetAddress addr("127.0.0.1", 6000);
    ChatServer server(&loop, addr, "ChatServer");

    server.start(); // 启动服务, listenfd epoll_atl=>epoll
    loop.loop();    // epoll_wait以阻塞方式等待新用户链接,已连接用户的读写事件等操作

    return 0;
}

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

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

相关文章

第一篇:Python简介:开启你的编程之旅

Python简介&#xff1a;开启你的编程之旅 在这个系列文章中&#xff0c;我将带领大家深入了解Python——一个极具魅力的编程语言。如果你对编程感兴趣&#xff0c;想要掌握一门既实用又强大的语言&#xff0c;那么Python无疑是一个绝佳的选择。本篇文章是这个系列的序章&#…

文件包含漏洞基础

php 中的文件包含函数&#xff1a; incude &#xff1a; require incude_once require_once 为了减少重复性代码的编写&#xff1b; 任意后缀的文件当中只要存在 php 代码就会被当作 php 执行&#xff1b; 本质&#xff1a;由于包含的文件不可控&#xff0c;导致文件包含…

S32K的JLINK与PE接线方法与刷程序失败问题

S32K的JLINK与PE接线方法与刷程序失败问题 1、PE的接线方法2、JLINK的接线方法3、刷程序失败问题 1、PE的接线方法 2、JLINK的接线方法 3、刷程序失败问题 出现如下问题&#xff1a; Secure Debug might be enabled on this device.lf so.please unlock the device via PEmic…

Maven基础篇4

跳过测试(了解) 1.背景 你的模块还没完成&#xff0c;项目经理就已经完成测试模块的开发 自己的模块写好提交测试&#xff0c;看看功能有没有完成&#xff0c;完成了那么就成功&#xff0c;否则失败&#xff1b; 使用背景&#xff1a; 1.测试用例写好了&#xff0c;自己模…

【计算机网络】成功解决 ARP项添加失败:请求的操作需要提升

最近在用Wireshark做实验时候&#xff0c;需要清空本机ARP表和DNS缓存&#xff0c;所以在cmd窗口输入以下命令&#xff0c; 结果发生了错误&#xff1a;ARP项添加失败&#xff1a;请求的操作需要提升 一开始我还以为是操作的命令升级了&#xff0c;但是后面发现其实只是给的权…

C++面向对象程序设计 - 继承与派生

面向对象技术强调软件的可重用性&#xff08;software reusability&#xff09;&#xff0c;C语言提供了类的继承机制&#xff0c;解决了软件重用问题。 C中所谓“继承”就是在一个已存在的类的基础上建立一个新类&#xff0c;从已有的类那里获得已有特性&#xff0c;叫做类的继…

网络协议深度解析:SSL、 TLS、HTTP和 DNS(C/C++代码实现)

在数字化时代&#xff0c;网络协议构成了互联网通信的基石。SSL、TLS、HTTP和DNS是其中最关键的几种&#xff0c;它们确保了我们的数据安全传输、网页的正确显示以及域名的正常解析。 要理解这些协议&#xff0c;首先需要了解网络分层模型。SSL和TLS位于传输层之上&#xff0c…

说说2024年暑期三下乡社会实践工作新闻投稿经验

作为一名在校大学生,我有幸自去年起参与学院组织的暑期大学生三下乡社会实践团活动。这项活动不仅是我们深入基层、服务社会的重要平台,也是展现当代大学生风采、传递青春正能量的有效途径。然而,如何将这些生动鲜活的实践故事、感人至深的瞬间传播出去,让更多人了解并受到启发…

在PostgreSQL中如何创建和使用自定义函数,包括内置语言(如PL/pgSQL)和外部语言(如Python、C等)?

文章目录 一、使用内置语言 PL/pgSQL 创建自定义函数示例代码使用方法 二、使用外部语言 Python 创建自定义函数安装 PL/Python 扩展示例代码使用方法 三、使用外部语言 C 创建自定义函数编写 C 代码编译为共享库在 PostgreSQL 中注册函数注意事项 总结 PostgreSQL 是一个强大的…

前端H5动态背景登录页面(下)

最近正好有点儿时间&#xff0c;把之前没整理完的前端动态背景登录页面给整理一下&#xff01;这是之前的连接前端H5动态背景登录页面&#xff08;上&#xff09;&#xff0c;这主要是两个登陆页面&#xff0c;一个彩色气泡&#xff0c;一个动态云朵&#xff0c;感兴趣的可以点…

08 内核开发-避免冲突和死锁-mutex

08 内核开发-避免冲突和死锁-mutex 课程简介&#xff1a; Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础&#xff0c;让他们能够理解和参与到Linux内核的开发过程中。 …

U盘无法正常格式化?教你一个强力的办法

前言 电脑格式化U盘或者移动硬盘的操作&#xff0c;相信各位小伙伴都是有一定经历的。 如果设备正常&#xff0c;那么进入到【此电脑】&#xff0c;在对应的分区点击【鼠标右键】-【格式化】就可以把对应的存储设备恢复到初始状态。 但凡事都会有例外&#xff0c;比如在格式化…

实验 | RT-Thread:L1

1 线程间同步 同步是指按预定的先后次序进行运行&#xff0c;线程同步是指多个线程通过特定的机制&#xff08;如互斥量&#xff0c;事件对象&#xff0c;临界区&#xff09;来控制线程之间的执行顺序&#xff0c;也可以说是在线程之间通过同步建立起执行顺序的关系&#xff0…

海外短剧:跨文化的新浪潮与看剧系统的搭建,海外短剧系统搭建开发定制

在全球化的大潮下&#xff0c;海外短剧作为一种新兴的文化交流方式&#xff0c;正逐渐受到越来越多人的喜爱。这种融合了各地文化元素、叙事手法新颖独特的短剧形式&#xff0c;不仅丰富了观众的视觉体验&#xff0c;也为影视媒体和想拓展海外市场的企业带来了无限商机。 一、…

【深度学习-第5篇】使用Python快速实现CNN分类(模式识别)任务,含一维、二维、三维数据演示案例(使用pytorch框架)

在之前的文章中介绍了CNN的图解入门&#xff0c;CNN的MATLAB分类实现&#xff0c;CNN的MATLAB回归实现。 卷积神经网络(Convolutional Neural Networ&#xff0c;简称CNN)是一种广泛应用于图像识别领域的深度学习算法。它通过模拟人类视觉系统的层次结构&#xff0c;可以自动提…

Docker NetWork (网络)

Docker 为什么需要网络管理 容器的网络默认与宿主机及其他容器都是相互隔离的&#xff0c;但同时我们也要考虑下面的一些问题&#xff0c; 比如 多个容器之间是如何通信的容器和宿主机是如何通信的容器和外界主机是如何通信的容器中要运行一些网络应用(如 nginx、web 应用、数…

HarmonyOS hsp制作与引用

1. HarmonyOS hsp制作与引用 1.1 介绍 HSP动态共享包&#xff08;模块&#xff09;,应用内HSP指的是专门为某一应用开发的HSP&#xff0c;只能被该应用内部其他HAP/HSP使用&#xff0c;用于应用内部代码、资源的共享。应用内HSP跟随其宿主应用的APP包一起发布&#xff0c;与该…

「deepin生态共建小组」正式启动招募!三大生态共建项目,速来 !

基于社区开源精神&#xff0c;为提高大家对deepin生态建设的参与感&#xff0c;应用商店将正式开放众多软件给广大开源爱好者进行维护。参与小组工作可获得多项专属小组福利&#xff0c;工作项目分为玲珑格式迁移、wine应用打包、deb原生应用维护。 招募条件 1&#xff09;不限…

【C/C++笔试练习】OSI分层模型、源端口和目的端口、网段地址、SNMP、状态码、tcp报文、域名解析、HTTP协议、计算机网络、美国节日、分解因数

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;OSI分层模型&#xff08;2&#xff09;源端口和目的端口&#xff08;3&#xff09;网段地址&#xff08;4&#xff09;SNMP&#xff08;5&#xff09;状态码&#xff08;6&#xff09;tcp报文&#xff08;7&#xff09;域…

使用python setup.py报错:Upload failed (403) / Upload failed (400)

当前报错的环境 Python 3.9.19twine1.15.0 本地~/.pypirc已正确配置了用户名和密码&#xff0c;用在pypi.org注册&#xff1a; [pypi]username skylerhupassword ${password}执行 python setup.py sdist upload -r pypi 打包上传到仓库报错。 在不久之前同样的环境&#…