muduo源码分析之TcpServer模块

article/2025/11/6 18:51:26

这次我们开始muduo源代码的实际编写,首先我们知道muduoLT模式,Reactor模式,下图为Reactor模式的流程图[来源1]

image-20220220154310731

然后我们来看下muduo的整体架构[来源1]

muduo

首先muduo有一个主反应堆mainReactor以及几个子反应堆subReactor,其中子反应堆的个数由用户使用setThreadNum函数设置,mainReactor中主要有一个Acceptor,当用户建立新的连接的时候,Acceptor会将connfd和对应的事件打包为一个channel然后采用轮询的算法,指定将该channel给所选择的subReactor,以后该subReactor就负责该channel的所有工作。

TcpServer类

我们按照从上到下的思路进行讲解,以下内容我们按照一个简单的EchoServer的实现思路来讲解,我们知道当我们自己实现一个Server的时候,会在构造函数中实例化一个TcpServer

EchoServer(EventLoop *loop,const InetAddress &addr, const std::string &name): server_(loop, addr, name), loop_(loop){// 注册回调函数server_.setConnectionCallback(std::bind(&EchoServer::onConnection, this, std::placeholders::_1));server_.setMessageCallback(std::bind(&EchoServer::onMessage, this,std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));// 设置合适的loop线程数量 loopthread 不包括baseloopserver_.setThreadNum(3);}

于是我们去看下TcpServer的构造函数是在干什么

TcpServer::TcpServer(EventLoop *loop,const InetAddress &listenAddr,const std::string &nameArg,Option option): loop_(CheckLoopNotNull(loop)), ipPort_(listenAddr.toIpPort()), name_(nameArg), acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), threadPool_(new EventLoopThreadPool(loop, name_)), connectionCallback_(), messageCallback_(), nextConnId_(1), started_(0)
{// 当有新用户连接时候,会执行该回调函数acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}

我们只需要关注acceptor_(new Acceptor(loop, listenAddr, option == kReusePort))threadPool_(new EventLoopThreadPool(loop, name_)) 首先很明确的一点,构造了一个Acceptor,我们首先要知道Acceptor主要就是连接新用户并打包为一个Channel,所以我们就应该知道Acceptor按道理应该实现socketbindlistenaccept这四个函数。

Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport): loop_(loop), acceptSocket_(createNonblocking()) // socket,acceptChannel_(loop, acceptSocket_.fd()), listenning_(false)
{acceptSocket_.setReuseAddr(true);acceptSocket_.setReusePort(true);acceptSocket_.bindAddress(listenAddr); // 绑定套接字// 有新用户的连接,执行一个回调(打包为channel)acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}

其中Acceptor中有个acceptSocket_,其实就是我们平时所用的listenfd,构造函数中实现了socketbind,而其余的两个函数的使用在其余代码

// 开启服务器监听
void TcpServer::start()
{// 防止一个TcpServer被start多次if (started_++ == 0) {threadPool_->start(threadInitCallback_); // 启动底层的loop线程池,这里会按照设定了threadnum设置pool的数量loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));}
}

我们知道,当我们设置了threadnum之后,就会有一个mainloop,那么这个loop_就是那个mainloop,其中可以看见这个loop_就只做一个事情Acceptor::listen

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

这里就实现了listen函数,还有最后一个函数accept,我们慢慢向下分析,从代码可以知道acceptChannel_.enableReading()之后就会使得这个listenfd所在的channel对读事件感兴趣,那什么时候会有读事件呢,就是当用户建立新连接的时候,那么我们应该想一下,那当感兴趣的事件发生之后,listenfd应该干什么呢,应该执行一个回调函数呀。注意Acceptor构造函数中有这样一行代码acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));这就是那个回调,我们去看下handleRead在干嘛。

// listenfd有事件发生了,就是有新用户连接了
void Acceptor::handleRead()
{InetAddress peerAddr;int connfd = acceptSocket_.accept(&peerAddr);if (connfd >= 0){// 若用户实现定义了,则执行,否则说明用户对新到来的连接没有需要执行的,所以直接关闭if (newConnectionCallback_){newConnectionCallback_(connfd, peerAddr); // 轮询找到subLoop,唤醒,分发当前的新客户端的Channel}else{::close(connfd);}}...
}

这里是不是就实现了accept函数,至此当用户建立一个新的连接时候,Acceptor就会得到一个connfd和其对应的peerAddr返回给mainloop,这时候我们在注意到TcpServer构造函数中有这样一行代码acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this,std::placeholders::_1, std::placeholders::_2));我们给acceptor_设置了一个newConnectionCallback_,于是由上面的代码就可以知道,if (newConnectionCallback_)为真,就会执行这个回调函数,于是就会执行TcpServer::newConnection,我们去看下这个函数是在干嘛。

void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{// 轮询算法选择一个subloop来管理对应的这个新连接EventLoop *ioLoop = threadPool_->getNextLoop(); char buf[64] = {0};snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);++nextConnId_;std::string connName = name_ + buf;LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s \n",name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());// 通过sockfd获取其绑定的本地ip和端口sockaddr_in local;::bzero(&local, sizeof local);socklen_t addrlen = sizeof local;if (::getsockname(sockfd, (sockaddr*)&local, &addrlen) < 0){LOG_ERROR("sockets::getLocalAddr");}InetAddress localAddr(local);// 根据连接成功的sockfd,创建TcpConnectionTcpConnectionPtr conn(new TcpConnection(ioLoop,connName,sockfd,   // Socket ChannellocalAddr,peerAddr));connections_[connName] = conn;// 下面的回调时用户设置给TcpServer,TcpServer又设置给TcpConnection,TcpConnetion又设置给Channel,Channel又设置给Poller,Poller通知channel调用这个回调conn->setConnectionCallback(connectionCallback_);conn->setMessageCallback(messageCallback_);conn->setWriteCompleteCallback(writeCompleteCallback_);// 设置了如何关闭连接的回调conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));// 直接调用connectEstablishedioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}

这里就比较长了,我先说下大概他干了啥事情:首先通过轮询找到下一个subloop,然后将刚刚返回的connfd和对应的peerAddr以及localAddr构造为一个TcpConnectionsubloop,然后给这个conn设置了一系列的回调函数,比如读回调,写回调,断开回调等等。下一章我们来说下上面的代码最后几行在干嘛。

自己的网址:www.shicoder.top 欢迎加群聊天 452380935 本文由博客一文多发平台 OpenWrite 发布!


http://chatgpt.dhexx.cn/article/TLE2Lwyr.shtml

相关文章

muduo网络库学习(1)

muduo网络库学习&#xff08;1&#xff09; 文章目录 muduo网络库学习&#xff08;1&#xff09;前言一、muduo是什么&#xff1f;二、代码结构1.base库2.net库3.附属库 二、网络库结构总结 前言 本章节主要介绍muduo网络库的整体架构&#xff01;一、muduo是什么&#xff1f;…

muduo

muduo 概述 muduo是基于Reactor模式的网络库&#xff0c;用于响应计时器和IO事件。 muduo采用基于对象而非面向对象的设计风格&#xff0c;其事件回调采用functionbind&#xff0c;用户在使用muduo的时候不需要继承其中的class 架构 Multiple Reactor Reactor模式&#xff1a…

muduo日志库原理以及源码分析

muduo日志库特点 日志批量写入批量唤醒写线程写日志用notifywait_timeout 方式触发日志的写入锁的粒度&#xff0c;双缓冲&#xff0c;双队列buffer默认 4M 缓冲区&#xff0c; buffers 是 buffer 队列&#xff0c; push 、 pop 时使用 move 语义 减少内存拷贝 muduo的这些特点…

muduo网络库与服务模型介绍

目录 一、muduo网络库简介 1、特点 2、代码结构 &#xff08;1&#xff09;公共接口 &#xff08;2&#xff09;内部实现 二、muduo线程模型 1、单线程Reactor 2、Reactor线程池 3、one loop per thread 4、one loop per thread 线程池 muduo是陈硕个人使用C开发的一…

muduo 架构解析

muduo是一个基于Reactor模式的C网络库。它采用非阻塞I/O模型&#xff0c;基于事件驱动和回调。我们不仅可以通过muduo来学习linux服务端多线程编程&#xff0c;还可以通过它来学习C11。     Reactor是网络编程的一般范式。我们这里从reactor模式为出发点&#xff0c;根据R…

muduo库介绍

muduo库是一个多线程服务器开发库 muduo 作者陈硕&#xff0c;现在在美国加州硅谷某互联网大公司工作&#xff0c;从事大规模分布式的可靠系统工程。这个库是作者多年工作的总结&#xff0c;可以说大家学通了这个库&#xff0c;找一份Linux服务器开发的工作是没问题的&#xf…

C++ muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装

Muduo is a multithreaded C network library based on the reactor pattern. muduo库的介绍就是&#xff1a;一个基于reactor反应堆模型的多线程C网络库。 muduo网络库是C语言开发的一个非常优秀的网络库&#xff0c;作者陈硕&#xff0c;muduo网络库在多线程环境下性能非常高…

遗传算法示例

遗传的概念&#xff1a; 遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型&#xff0c;是一种通过模拟自然进化过程搜索最优解的方法。 遗传算法的特点&#xff1a; 对于搜索算法的共同特征有 首先组成一组候选解。依据某些使用性条件测算这些…

10分钟搞懂遗传算法

大自然有种神奇的力量&#xff0c;它能够将优良的基因保留下来&#xff0c;从而进化出更加强大、更加适合生存的基因。遗传算法便基于达尔文的进化论&#xff0c;模拟了自然选择&#xff0c;物竞天择、适者生存&#xff0c;通过N代的遗传、变异、交叉、复制&#xff0c;进化出问…

遗传算法简单实例

遗传算法的手工模拟计算示例 为更好地理解遗传算法的运算过程&#xff0c;下面用手工计算来简单地模拟遗传算法的各 个主要执行步骤。 例&#xff1a;求下述二元函数的最大值&#xff1a; (1) 个体编码 遗传算法的运算对象是表示个体的符号串&#xff0…

遗传算法(基础知识)

遗传算法&#xff08;基础知识&#xff09; 遗传算法简称GA&#xff08;Genetic Algorithms&#xff09;模拟自然界生物遗传学&#xff08;孟德尔&#xff09;和生物进化论&#xff08;达尔文&#xff09;通过人工方式所构造的一类 并行随机搜索最优化方法&#xff0c;是对生物…

遗传算法概念、步骤、应用解析(案例直白--黄含驰)

遗传算法 ①  在几十亿年的演化过程中&#xff0c;自然界中的生物体已经 形成了一种优化自身结构的内在机制&#xff0c;它们能够不 断地从环境中学习&#xff0c;以适应不断变化的环境  对于大多数生物体&#xff0c;这个过程是通过自然选择和有性生殖来完成的。自然选择…

遗传算法超详细图解

遗传算法&#xff08;Genetic Algorithm&#xff09;顾名思义&#xff0c;是一种基于自然选择原理和自然遗传机制的启发式搜索算法。该算法通过模拟自然界中生物遗传进化的自然机制&#xff08;选择、交叉和变异操作&#xff09;&#xff0c;将好的遗传基因&#xff08;最优目标…

遗传算法及其应用

一、遗传算法的定义 遗传算法的基本思想是参考生物学中物种“物竞天择&#xff0c;适者生存”的思想。在计算机中&#xff0c;通过给定约束条件&#xff0c;使初始参数不断迭代&#xff0c;从而接近最优解。 遗传算法可描述为&#xff1a; Initialize population process-chr…

详解遗传算法(含MATLAB代码)

目录 一、遗传算法概述 二、遗传算法的特点和应用 三、遗传算法的基本流程及实现技术 3.1 遗传算法的基本流程 3.2 遗传算法的实现技术 1.编码 2.适应度函数 3.选择算子 4.交叉算子 5.变异算子 6.运行参数 四、遗传算法的基本原理 4.1 模式定理 4.2 积木块假设 …

遗传算法步骤

遗传算法是一种模拟生物自然进化的一种算法&#xff0c;通话对生物进化的模拟&#xff0c;实现对数值函数的模拟计算。它主要分为四个步骤&#xff1a;初始化、杂交、变异和选择。相关实现可参考https://github.com/ShaquallLee/evolutionary-programming/tree/master/aEP 1、…

遗传算法原理+程序案例详解

注明&#xff1a;这篇遗传算法程序我在网上看到多次&#xff0c;很多人在转载时&#xff0c;都称已经修改了错误的地方&#xff0c;程序在matlab上能够运行。 当我在学习这段程序时&#xff0c;发现结果仍存在很大问题(不稳定、不准确)。我一行一行看时&#xff0c;发现不仅有少…

遗传算法、遗传算法库函数ga和gamultiobj、遗传算法工具箱GOT实例介绍

目录 前言 适应度函数和目标函数的关系 1. 常规遗传算法 2.结合非线性规划fmincon函数的遗传算法 2.1 fmincon非线性规划函数使用 2.2 结合非线性规划fmincon函数的遗传算法使用及示例 2.2.1 编码 2.2.2 选择 2.2.3交叉 2.2.4变异 2.2.5非线性规划fmincon函数 2.2.…

遗传算法原理与应用详解

遗传算法 ( GA , Genetic Algorithm ) &#xff0c;也称进化算法 。 遗传算法是受达尔文的进化论的启发&#xff0c;借鉴生物进化过程而提出的一种启发式搜索算法。因此在介绍遗传算法前有必要简单的介绍生物进化知识。 一.进化论知识 作为遗传算法生物背景的介绍&#xff0…

遗传算法(一) 遗传算法的基本原理

遗传算法&#xff08;一&#xff09;遗传算法的基本原理 1.概述 遗传算法&#xff08;Genetic Algorithm, GA&#xff09;起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法&#xff0c;借鉴了达尔文的进化论和孟德尔的遗…