[muduo网络库]——muduo库Acceptor类(剖析muduo网络库核心部分、设计思想)

接着之前我们剖析的muduo库三大核心组件Channel类,Poller/EpollPoller类,EventLoop类,我们接下来继续看muduo库中的其他类,这一篇,我们先来介绍Acceptor类。

Acceptor类

主要功能

Acceptor类用于创建套接字,设置相关处理方法,调用listen函数,接受(accept)客户端连接, 接受新用户连接并分发连接给SubReactor(SubEventLoop)。注意: 它只在muduo网络库内部的TcpServer使用,由TcpServer控制它的生命期。

重要成员变量

EventLoop *loop_; //Acceptor用的就是用户定义的那个baseloop_,也就是mainloop
Socket acceptSocket_;
Channel acceptChannel_;
NewConnectionCallback newConnetionCallback_;
bool listenning_;
  • loop_监听套接字的fd由哪个EventLoop负责循环监听以及处理相应事件,其实这个EventLoop就是main EventLoop。
  • acceptSocket_ 服务器监听套接字的文件描述符
  • acceptChannel_把acceptSocket_及其感兴趣事件和事件对应的处理函数进行封装。
  • newConnetionCallback_这个是最重要的一个成员了,它的类型是using NewConnectionCallback = std::function<void(int sockfd, const InetAddress&)>;,在TcpServer构造函数中通过acceptor_->setNewConnetionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1,std::placeholders::_2)); TcpServer::newConnection函数注册给了这个成员变量。这个 TcpServer::newConnection函数的功能是通过轮询EventLoop *ioLoop = threadPool_->getNextLoop();选择一个subEventLoop,并把已经接受的连接分发给这个subEventLoop。
  • listenning_是一个标志位

重要成员函数

  • 首先来提一下构造函数
Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool resuseport): loop_(loop), acceptSocket_(createNonblocking()) //创建sock, acceptChannel_(loop, acceptSocket_.fd()) //封装成channel, listenning_(false)
{acceptSocket_.setReuseAddr(true); //更改TCP选项acceptSocket_.setReusePort(true); acceptSocket_.bindAddress(listenAddr); //绑定套接字acceptChannel_.setReadCallback(std::bind(&Acceptor::headleRead,this));
}

1)要知道Acceptor是TcpServer管理的,在构造函数中,首先是TcpServer给的loop,这里实际就是mainloop;
2)其次通过createNonblocking中利用socket创建了一个套接字,这个socket是监听套接字;一个服务器通常只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。而内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字在accept()函数中,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭;
3)将loop和socket封装成channel
4)给listenning_一个初始化
5)通过调用Socket中的setReuseAddrsetReusePort更改了一些选项。
6)绑定了套接字
7)绑定一个回调,用于新用户的连接

  • listen( )函数
void Acceptor::listen()
{listenning_ = true;acceptSocket_.listen(); //listen acceptChannel_.enableReading(); //acceptChannel_=> Poller
}

在这里,我们可以看出实际上调用了Socketlisten( ),然后底层调用了系统的listen( ),开启对acceptSocket_的监听同时将acceptChannel及其感兴趣事件(可读事件)注册到main EventLoop的事件监听器上。换言之就是让mainLoop事件监听器去监听acceptSocket_;

  • headleRead()函数
void Acceptor::headleRead()
{InetAddress peerAddr;int connfd = acceptSocket_.accept(&peerAddr);if(connfd >= 0){if (newConnetionCallback_){newConnetionCallback_(connfd,peerAddr);//轮询找到SUBLOOP唤醒,分发当前的新客户端的Channel}else{::close(connfd);}}else{LOG_ERROR("%s:%s:%d accept err:%d \n", __FILE__,__FUNCTION__,__LINE__,errno); if (errno == ENFILE){LOG_ERROR("%s:%s:%d sockfd reached limit! \n", __FILE__,__FUNCTION__,__LINE__); } }
}

这里主要是建立连接,通过调用Socket的accept函数,底层调用系统的accept函数,返回一个已连接的socket描述字,这样连接就建立了。同时内部还调用了成员变量newConnectionCallback_保存的函数,当mainLoop监听到acceptChannel_上发生了可读事件时(新用户连接事件),就是调用这个handleRead( )方法,内部调用newConnetionCallback_,也就是TcpServer设置的一个回调函数setNewConnetionCallback,绑定了TcpServer::newConnection,通过 轮询算法,选择一个subloop,分发当前的新客户端的Channel,并且绑定了一些回调。

需要注意的是:在muduo库的源码中,实际上还创建了一个空的文件描述符idleFd_

这个思想也是很巧妙的,在调用accept的过程中,如果已用文件描述符过多,accept会返回-1,构造函数中注册的idleFd_就派上用场了。当前文件描述符过多,无法接收新的连接。但是由于我们采用LT模式,如果无法接收,可读事件会一直触发。那么在这个地方的处理机制就是,关掉之前创建的空的idleFd_,然后去accept,这样进行了连接,让这个事件不会一直触发,然后再关掉该文件描述符,重新将它设置为空文件描述符。这样就优雅的解决 EMFIFE 问题。

代码地址:https://github.com/Cheeron955/mymuduo/tree/master

好了~ 关于muduo库的Acceptor类就剖析到这里,要记住它是由TcpServer来管理的,所以在TcpServer我们也会再次提到它。最后,下一篇我们来剖析Socket类 ~ 我们下一节见 ~~

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

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

相关文章

企业OA办公系统开发笔记:1、搭建后端环境

文章目录 企业办公系统&#xff1a;搭建环境一、项目介绍1、介绍2、技术栈3、项目模块4、数据库 二、搭建环境1、搭建后端1.1、搭建父工程clfwzx-oa-parent1.2、搭建工具类父模块common1.3、搭建工具类common的子模块1.4、搭建实体类模块model和项目模块service-oa 2、配置依赖…

亲测!史上最全数据库基础?!

为什么要学习数据库 以前在程序中存储数据是一个变量&#xff0c;对象&#xff1b;数据都存储在内存中&#xff0c;程序运行结束后就销毁。 后来学习IO之后&#xff0c;将数据存储在文件中&#xff0c;做到持久存储&#xff0c;但是使用不方便。 学习专业的数据存储软件——…

基于POSIX的信号量模拟DAG上的并行计算的同步问题

本代码主题借鉴nju的jyy老师的代码 自己增加了随机生成DAG(有向无环图)(不保证连通)数据进行测试 运行打印结果即为并行计算DAG的拓扑序 #include <pthread.h> #include <semaphore.h> #include <unistd.h> #include <iostream> #include <vector&g…

2024最新最全【NMAP】零基础入门到精通

一、Nmap介绍 Nmap(Network Mapper&#xff0c;网络映射器)是一款开放源代码的网络探测和安全审核工具。它被设计用来快速扫描大型网络&#xff0c;包括主机探测与发现、开放的端口情况、操作系统与应用服务指纹识别、WAF识别及常见安全漏洞。它的图形化界面是Zenmap&#xff…

[AIGC] redis 持久化相关的几道面试题

文章目录 1. 什么是Redis持久化&#xff1f;2. Redis 的持久化机制是什么&#xff1f;各自的优缺点&#xff1f;2.1 RDB&#xff08;Redis DataBase&#xff09;&#xff0c;快照2.2 AOF&#xff08;Append Only File&#xff09;&#xff0c;日志 3. 优缺点是什么&#xff1f;…

Vue3的setup

Vue3的setup setup选项是一个接收props和context的函数是一个新的组件选项&#xff0c;作为Composition-API的入口点&#xff0c;只会被执行一次&#xff0c;用于建立数据与逻辑的连接。 注意点 在执行setup函数时&#xff0c;还没执行created生命周期方法&#xff0c;因此在s…

单核CPU调度

CPU MLFQ 调度 MLFQ即多级反馈队列调度。在给定时间片中&#xff0c;任务存在不同优先队列之中等待被执行&#xff0c;MLFQ根据优先级去决定哪个任务在该时间片执行 Round Robin Round Robin即RR&#xff0c;是基于时间片的轮询调度算法。给每个任务分配一个时间片&#xff…

pixhawk无人机飞控解锁

飞控解锁 GitBook 左手油门的遥控解锁是油门右下角拨&#xff0c;右手油门是油门最低&#xff0c;方向最右。 飞控如何加锁? 左手油门&#xff1a;油门左下角 右手油门&#xff1a;油门最低&#xff0c;方向最左 飞控解锁成功后&#xff0c;不推油门的情况下&#xff0c;…

基于SSM+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

大众点评全国店铺基础信息采集-学习培训店铺-2024年5月

2024年5月最新采集大众点评全国(内地)-学习培训大类-店铺基础信息&#xff0c;93余万家 学习培训类店铺示例&#xff1a; 店铺id k40VtNBN3bixFJIU 店铺名称 梦想钢琴成人钢琴(珠江新城总部) 十分制效果评分 9.4 十分制服务评分 9.4 十分制环境评分 9.4 人均价格 1233 …

为什么数据库字符编码不一致会导致索引失效

引言 数据库字符编码不一致是数据库管理和优化过程中经常遇到的问题之一&#xff0c;尤其在涉及多语言环境和多应用时更为显著。本文旨在深入探讨字符编码不匹配如何影响SQL查询性能&#xff0c;导致索引失效&#xff0c;以及其背后的原理。 1. 字符编码与索引基础 字符编码…

【TypeScript模块简介以及使用方法】

TypeScript模块简介 TypeScript中的模块&#xff08;Modules&#xff09;是代码的封装体&#xff0c;它们可以包含变量、函数、类和接口等。在TypeScript中&#xff0c;模块可以被其他模块引用和使用&#xff0c;从而实现代码的复用和模块化开发。 TypeScript支持两种模块系统…

LORA学习笔记2——训练集处理

前言 对于ai训练来说&#xff0c;处理训练集是模型训练的重要环节。训练集的质量对最终模型的质量影响巨大。这里以二次元角色为例&#xff0c;记录下训练集处理的流程和一些心得。 素材准备 素材准备有以下几个需要注意的点&#xff1a; 通常训练二次元角色需要30张以上的…

14:HAL---CRC校验

103系列只有一个CRC 前言&#xff1a; CRC&#xff08;Cyclic Redundancy Check&#xff09;&#xff0c;即循环冗余校验&#xff0c;是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法&#xff0c;主要用来检测或校核数据传输或者保存后可能出现的错误。…

QX---mini51单片机学习---(8)8*8点阵屏

目录 1LED点阵屏简绍 2 8*8点阵屏电路图74 3 74HC595芯片 4实践编程 1LED点阵屏简绍 2 8*8点阵屏电路图74 怎么点亮&#xff0c;正极给高负极给低 不能同时静态显示&#xff0c;跟数码管动态显示一样&#xff0c;反复横跳&#xff0c;利用视觉效果 3 74HC595芯片 …

斐波那契数

509. 斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;其中 …

第四届上海理工大学程序设计全国挑战赛---昨日方舟

知识点&#xff1a;模拟 题目描述 《昨日方舟》是一款塔防类游戏。在游戏中&#xff0c;我们要通过部署角色来抵御怪物的入侵。在这款游戏中&#xff0c;有一名角色名字为 “今”&#xff0c;他的能力为能够在地图上部署小蛇&#xff0c;小蛇在某些条件下可以与其他小蛇合体…

关于 IIS 开启匿名访问网站仍要账号密码登录网站的解决方法

欢迎关注公总号【云边小网安】 问题提出&#xff1a;发现虽然勾选了允许匿名访问网站&#xff0c;但在访问某一网站的时候仍然需要登录账号密码 解决方法一&#xff1a;登录管理员账号密码解决方法二&#xff1a;添加访问网站文件夹的用户 访问某一网站本质上来讲&#xff0…

C++入门必读-Qt的安装与配置

QT简介 Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立图形界面所需的所有功能。它是完全面向对象的&#xff0c;很容易扩展&#xff0c;并且允许真正的组件编程。 QT下载 访问下载网站: Index of /archive/qt 安装编译器 QT安装 建议安装之前将网络断…

1064 朋友数

solution 给出n个整数&#xff0c;统计可能的位数和&#xff0c;并按升序输出&#xff08;考虑用set实现&#xff09; #include<iostream> #include<set> using namespace std; int main(){set<int> st;int n, x, sum;scanf("%d", &n);while…