【Muduo】接收新连接的Acceptor类

在 Muduo 的设计中,Acceptor类扮演着接受客户端连接请求的关键角色,其运行在每一个TcpServer实例中。一个服务器通常只创建一个监听socket描述字,故其在TcpServer中只有一个,用来监听服务器的唯一socket。它也会将传来的mainLoop和acceptSocket封装成一个Channel,这个Channel只对读事件感兴趣,也就是说,只通过回调函数 handleRead() 处理有新客户端连接请求的事件。

成员变量

  • EventLoop* loop_:指向EventLoop的指针,用于处理 I/O 事件。这个loop是mainloop,负责监听服务器的socket,并且接受客户端的连接请求。
  • Channel acceptChannel_:用于监听服务器 socket 的可读事件(即新的连接请求)。Channel 是 Muduo 中的一个重要类,它封装了文件描述符(file descriptor)和与其相关的事件监听和处理逻辑。
  • bool listenning_:表示是否正在监听新的连接请求。
  • Socket acceptSocket_:Acceptor 会创建一个监听套接字,并绑定到一个特定的 IP 地址和端口上。这个套接字被设置为非阻塞模式,并使用 listen() 函数开始监听连接请求
  • std::function<void(int)> newConnectionCallback_:当接受到新的连接时调用的回调函数。这允许用户自定义如何处理新的连接。

成员函数

  • 构造函数:接收TcpServer传来的mainLoop指针,初始化成员变量,设置监听地址和端口,创建 socket,并将 socket 绑定到指定的地址和端口。
  • listen()Acceptor 会创建一个监听套接字,并绑定到一个特定的 IP 地址和端口上。这个套接字被设置为非阻塞模式,并使用 listen() 函数开始监听连接请求。调用Socket类中封装的操作系统的相关函数(如 ::listen() )来监听 socket 的可读事件。
  • handleRead():处理可读事件(即新的连接请求)的回调函数。当 EventLoop检测到 socket 上有可读事件时,它会调用这个函数。在这个函数中,Acceptor会接受新的连接,并调用用户提供的回调函数 newConnectionCallback_
  • setNewConnectionCallback():设置处理新连接的回调函数。Acceptor 需要一个回调函数来处理新的连接请求。当有新的连接请求到达时,Acceptor 会调用这个回调函数,并传入一个已连接的套接字(通常是 TCPSocket 的实例)。
  • 其他辅助函数:如关闭 socket、检查是否正在监听等。

作用

Acceptor类的主要作用是监听服务器 socket 上的连接请求,并在接受到新的连接时调用TcpServer的 newConnection 回调函数。它是 Muduo 网络库中的一个重要组件,负责处理与客户端建立连接的过程。通过 Acceptor,服务器可以持续监听来自客户端的连接请求,并在需要时接受新的连接。这使得服务器能够同时处理多个客户端的连接请求,从而实现高并发的网络通信。

源码

Acceptor.h
#pragma once#include "noncopyable.h"
#include "Socket.h"
#include "Channel.h"#include <functional>class EventLoop;
class InetAddress;// Acceptor用的就是用户定义的那个baseloop,也即mainLoop
class Acceptor : noncopyable
{
public:using NewConnectionCallback = std::function<void(int sockfd, const InetAddress &)>;Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reusePort);~Acceptor();// TcpServer的构造函数中设置的TcpServer::newConnection方法void setNewConnectionCallback(const NewConnectionCallback &cb){newConnectionCallback_ = std::move(cb);}void listen();bool listenning() const { return listenning_; }private:void handleRead();EventLoop *loop_; // Acceptor用的就是用户定义的那个baseloop,也即mainLoopSocket acceptSocket_;Channel acceptChannel_;NewConnectionCallback newConnectionCallback_; // 在TcpServer::TcpServer()中设置,将新连接打包bool listenning_;
};
Acceptor.cc
#include "Acceptor.h"
#include "InetAddress.h"
#include "LogStream.h"#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>// 创建一个非阻塞的sockfd
static int createNonblocking()
{int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); // SOCK_CLOEXEC标志子进程不接受父进程if (sockfd < 0){LOG_FATAL << "sockets::createNonblockingOrDie error, errno:" << errno;}return sockfd;
}Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reusePort): loop_(loop), acceptSocket_(createNonblocking()) // 创建套接字socket, acceptChannel_(loop, acceptSocket_.fd()), listenning_(false)
{acceptSocket_.setReuseAddr(true); // 设置tcp选项acceptSocket_.setReusePort(true);acceptSocket_.bindAddress(listenAddr); // bind// TcpServer::start()方法中,调用Acceptor.listen()// baseLoop =》 acceptChannel(listendfd)// 有新用户连接,要执行一个回调,connfd->channel->subloopacceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this)); // acceptChannel_只关心读事件
}Acceptor::~Acceptor()
{acceptChannel_.disableAll(); // 取消fd所有的事件状态acceptChannel_.remove();
}void Acceptor::listen()
{LOG_DEBUG << "Acceptor::listen()";listenning_ = true;acceptSocket_.listen();acceptChannel_.enableReading(); // 将accpetorChannel注册在baseLoop的epoll
}void Acceptor::handleRead()
{InetAddress peerAddr;int connfd = acceptSocket_.accept(&peerAddr); // 获取到已连接addrLOG_DEBUG << "connfd=" << connfd << "  peerAddr:" << peerAddr.toIpPort();if (connfd >= 0){if (newConnectionCallback_){newConnectionCallback_(connfd, peerAddr);}else{ // 来了新连接,但是没有对应的回调函数,即无法为这个客户端服务,则直接关闭::close(connfd);}}else{LOG_ERROR << "Acceptor::handleRead():acceptSocket_.accept error, errno: " << errno;if (errno == EMFILE){LOG_ERROR << "Acceptor::handleRead() error, sockfd reached limit!";}}
}

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

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

相关文章

spring boot集成Knife4j

文章目录 一、Knife4j是什么&#xff1f;二、使用步骤1.引入依赖2.新增相关的配置类3.添加配置信息4.新建测试类5. 启动项目 三、其他版本集成时常见异常1. Failed to start bean ‘documentationPluginsBootstrapper2.访问地址后报404 一、Knife4j是什么&#xff1f; 前言&…

Todesk无法登录,提示服务器断开连接。(已解决)

坐标福建&#xff0c;近一两个月todesk手机端均无法登录&#xff0c;尝试卸载重装&#xff0c;更新等&#xff0c;均无效。也没搜索到有效的解决方案&#xff0c;今天去看了商店的低星评论&#xff0c;发现是针对福建地区的服务器“维护”&#xff0c;考虑到近期复杂的国际形势…

大语言模型实战——最小化agent

1. agent是什么 大模型拥有语言理解和推理能力后&#xff0c;就相当于拥有了大脑&#xff0c;要让模型发挥更大的潜力&#xff0c;就需要给它安装上手臂&#xff0c;让它拥有行动的能力。 而Agent就是一个将语言模型和外部工具结合起来的智能体&#xff0c;它使用语言模型的推…

“从根到叶:使用决策树导航数据”

目录 一、说明 二、什么是决策树&#xff1f; 三、基本概念&#xff1a; 四、工作原理&#xff1a; 五、分类原理分析 5.1 信息熵&#xff1a; 5.2 信息增益&#xff1a; 5.3 基尼杂质&#xff1a; 5.4 基尼系数和熵的区别&#xff1a; 六、对于回归决策树&#xff1a; 6.1 均方…

解决el-image只能点击关闭按钮才能关闭的问题

问题&#xff1a;el-image打开大图预览时&#xff0c;只能点击关闭按钮才能关闭&#xff0c;点击蒙层不能关闭的 methods: {handleClickStop() {this.$nextTick(() > {const domImageView document.querySelector(".el-image-viewer__mask") // 获取遮罩层domif …

DOM【事件、操作节点、DOM案例】--学习JavaEE的day49

day49 JS核心技术 DOM 继day48 事件 键盘事件 监听器&#xff1a;onkeydown、onkeypress、onkeyup <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><input type"text&q…

考研英语二小作文专项练习题目和简单示例

目录 一、考研英语小作文介绍 二、往年真题练习 题目一(给俱乐部写封电子邮件) 三、作者复习经验

前端请求超时截断,axios timeout设置未生效情况记录

问题描述 前端请求超时截断&#xff0c;axios timeout设置未生效情况记录 timeout设置方式&#xff1a; 表现&#xff08;前端超过5min报错500&#xff0c;直接访问接口超过5min能够正常响应&#xff09;&#xff1a; 问题原因 上面的配置设置时间为1000min&#xff0c;明显…

「TypeScript系列」TypeScript 接口/接口继承

文章目录 一、TypeScript 接口1. 属性接口2. 方法接口3. 可选属性和只读属性4. 索引签名 二、TypeScript 接口继承1. 单继承2. 多继承的替代方案 三、TypeScript 接口与数组四、TypeScript 接口与联合类型五、相关链接 一、TypeScript 接口 在 TypeScript 中&#xff0c;接口&…

前端开发攻略---三种方法解决Vue3图片动态引入问题

目录 1、将图片放入public文件夹中 2、使用 /src/.... 路径开头 3、生成图片的完整URL地址&#xff08;推荐&#xff09; 1、将图片放入public文件夹中 使用图片&#xff1a;路径为 /public 开头 <template><div><img :src"/public/${flag ? 01 : 02}.jp…

【电子学会】2023年09月图形化一级 -- 芝麻开门

芝麻开门 1. 准备工作 &#xff08;1&#xff09;删除小猫角色&#xff0c;添加角色Key&#xff1b; &#xff08;2&#xff09;删除白色背景&#xff0c;添加背景Castle 1和Pathway。 2. 功能实现 &#xff08;1&#xff09;点击绿旗&#xff0c;钥匙在舞台中间&#xff…

有序的一维数组中插入一个整数并保持其有序性

在C语言中&#xff0c;如果你想在一个有序的一维数组中插入一个整数并保持其有序性&#xff0c;你可以使用指针来操作数组元素。这里有一个基本的步骤和示例代码来展示这个过程&#xff1a; 定义一个足够大的数组&#xff08;比原数组多一个位置来存放新元素&#xff09;。 初…

SQL——SELECT相关的题目

目录 197、上升的温度 577、员工奖金 586、订单最多的客户 596、超过5名学生的课 610、判断三角形 620、有趣的电影 181、超过经理收入的员工 1179、重新格式化部门表 1280、学生参加各科测试的次数 1068、产品销售分析I 1075、项目员工I 1084、销售分析III 1327、列出指…

2024最新 Jenkins + Docker 实战教程(六)- Jenkins配置邮箱接收构建通知

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Spring Cloud 面试题(二)

1. 什么是 Hystrix&#xff1f;它如何实现容错&#xff1f; Hystrix是一个开源的容错库&#xff0c;由Netflix开发&#xff0c;用于分布式系统中的服务间调用&#xff0c;以防止任何单一服务的故障导致整个系统的崩溃。Hystrix通过提供快速失败&#xff08;fail-fast&#xff…

java适配器模式 (Adapter Pattern)示例代码

适配器模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口。这种模式通常用于系统间接口不兼容的情况下&#xff0c;通过适配器来让它们能够一起工作。下面是一个简单的Java适配器模式示例代码。 目标接口 首先&#xff0c;我们定义了目…

【数据结构】二叉树的功能实现

文章目录 关于二叉树的创建如何创建二叉树实现二叉树的前、中、后序遍历层序遍历 关于二叉树的创建 在笔者的上一篇文章中堆进行了一个详细介绍&#xff0c;而二叉树是以堆为基础进行创建&#xff0c;它与堆的显著不同是 堆像是一个线性结构&#xff0c;堆的结构往往是一个数…

PHP生成二维码+二维码包含logo图片展示

composer require chillerlan/php-qrcode 用到的扩展自己安装&#xff08;注&#xff1a;只生成二维码只要开gd扩展就行&#xff09; 仅生成二维码看这个&#xff1a; use chillerlan\QRCode\QRCode;public function QRCode(){$qrcode new QRCode();$url "http://ww…

Beta 分布和 Gamma 分布

0. 摘要 本文主要介绍 B e t a Beta Beta 分布和 G a m m a Gamma Gamma 分布之间的关系, 以及两者的采样方法. 其实, PyTorch、Numpy、Scipy 等一些机器学习包已经实现了对这两种分布的包装, 本文主要目的是理解背后的大致原理. 1. Beta 分布 设 X ∼ B e t a ( α , β…