本贴用于记录muduo库的学习过程,以下是关于TcpServer的个人理解。

TcpServer内含Acceptor、threadpool等类,算是把主线程所有要做的事封装了起来。

重要成员变量

EventLoop *loop_; // baseloop 用户自定义的loopconst std::string ipPort_;const std::string name_;std::unique_ptr<Acceptor> acceptor_; // 运行在mainloop 任务就是监听新连接事件std::shared_ptr<EventLoopThreadPool> threadPool_; // one loop per threadConnectionCallback connectionCallback_;       //有新连接时的回调MessageCallback messageCallback_;             // 有读写事件发生时的回调WriteCompleteCallback writeCompleteCallback_; // 消息发送完成后的回调ThreadInitCallback threadInitCallback_; // loop线程初始化的回调int numThreads_;//线程池中线程的数量。std::atomic_int started_;int nextConnId_;ConnectionMap connections_; // 保存所有的连接

loop_:代表baseloop。

acceptor_:用来监听和接收新连接。

threadPool_:用于管理线程。

started_:是否启动的标志。用atomic_int定义为了维护线程安全。

nextConnId:表示是第几个连接。

connections_:保存所有的tcpconnection指针。

重要成员函数

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类中绑定的acceptChannel_会有读事件发生,执行handleRead()调用TcpServer::newConnection回调acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}

构造函数,acceptor和threadpool都是new出来的,但是eventloop是外部输入的,为什么这样设计?我感觉是为了让生命周期更清晰,loop由外部输入,结束时tcpserver先析构,loop再析构,这样不会存在server调用不存在loop的情况。希望知道的朋友可以告诉我。

void TcpServer::setThreadNum(int numThreads)
{int numThreads_=numThreads;threadPool_->setThreadNum(numThreads_);
}

设置要开启多少线程。

void TcpServer::start()
{if (started_.fetch_add(1) == 0)    // 防止一个TcpServer对象被start多次{threadPool_->start(threadInitCallback_);    // 启动底层的loop线程池loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));}
}

tecpserver的启动函数。fetch_add(1)将started_原子性地+1,并返回旧值。

void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{// 轮询算法 选择一个subLoop 来管理connfd对应的channelEventLoop *ioLoop = threadPool_->getNextLoop();char buf[64] = {0};snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);++nextConnId_;  // 这里没有设置为原子类是因为其只在mainloop中执行 不涉及线程安全问题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;::memset(&local, 0, sizeof(local));socklen_t addrlen = sizeof(local);if(::getsockname(sockfd, (sockaddr *)&local, &addrlen) < 0){LOG_ERROR("sockets::getLocalAddr");}InetAddress localAddr(local);TcpConnectionPtr conn(new TcpConnection(ioLoop,connName,sockfd,localAddr,peerAddr));connections_[connName] = conn;// 下面的回调都是用户设置给TcpServer => TcpConnection的,至于Channel绑定的则是TcpConnection设置的四个,handleRead,handleWrite... 这下面的回调用于handlexxx函数中conn->setConnectionCallback(connectionCallback_);conn->setMessageCallback(messageCallback_);conn->setWriteCompleteCallback(writeCompleteCallback_);// 设置了如何关闭连接的回调conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}

当acceptor的channel触发事件,进行这个函数回调。getsockname得到此连接对应的本地端口。我们已经获得了连接的socket,接收和发送信息都通过这个socket,为什么还要tcpconnection保存对方的地址peerAddr。比如有人进攻你的网站,你需要一个黑白名单,就可以通过这个peeraddr来设置。

void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{LOG_INFO("TcpServer::removeConnectionInLoop [%s] - connection %s\n",name_.c_str(), conn->name().c_str());connections_.erase(conn->name());EventLoop *ioLoop = conn->getLoop();ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}

当要移除一个连接时,先将removeConnectionInLoop函数放入所属线程等待执行,erase移除在tcpserver里的conn指针,由于conn也是一个shared_ptr(由shared_from_this()传入),所以不会直接销毁,在启动connectiondestroyed函数,对conn内的事件取消监听,结束后自动销毁TCPConnection。

TcpServer::~TcpServer()
{for(auto &item : connections_){TcpConnectionPtr conn(item.second);item.second.reset();    // 把原始的智能指针复位 让栈空间的TcpConnectionPtr conn指向该对象 当conn出了其作用域 即可释放智能指针指向的对象// 销毁连接conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed, conn));}
}

当tcpserver要析构时,遍历connections_,reset用于将该智能指针设置为空,再销毁该tcpconnection。


以上就是我对TcpServer类的理解,欢迎大家交流讨论。

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

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

相关文章

工作两年,最后从css转向tailwind了!

菜鸟上班已经两年了&#xff0c;从一个对技术充满热情的小伙子&#xff0c;变成了一个职场老鸟了。自以为自己在不停的学习&#xff0c;但是其实就是学一些零碎的知识点&#xff0c;比如&#xff1a;vue中什么东西没见过、js什么特性没用过、css新出了个啥 …… 菜鸟感觉自己也…

macOS 更新后找不到钥匙串访问工具的解决方案

macOS 更新后找不到钥匙串访问工具的解决方案 随着macOS的不断更新&#xff0c;一些系统工具的位置可能会发生变化&#xff0c;给用户带来不便。钥匙串访问&#xff08;Keychain Access&#xff09;是macOS中一个非常重要的工具&#xff0c;用于管理密码、证书等敏感信息。最近…

深入理解Go 与 PHP 在参数传递上的核心区别

$run_return_data []; $ret $this->handleData($event_req_info, $run_return_data); public function handleData($event_req_info, &$run_return_data): array {$run_return_data [ //使用引用变量返回数据shop_id > $shop_id,request_id > $request_…

【Dify智能体】2025 最新版Linux部署Dify教程(Ubuntu)

一、前言 Dify 是一款开源的智能体工作流平台,可以用来快速构建 AI 应用。相比手动搭建复杂的依赖环境,Docker Compose 部署方式更简单、更快速、更稳定。本文将一步步带你在 Ubuntu 22.04 + Docker Compose v2 上安装 Dify,并给出常见问题与优化方案。 ps:如果还没有安装…

基础思想:动态规划与贪心算法

一、动态规划核心思想&#xff1a;将复杂问题分解为相互重叠的子问题&#xff0c;通过保存子问题的解来避免重复计算&#xff08;记忆化&#xff09;。动态规划需要通过子问题的最优解&#xff0c;推导出最终问题的最优解&#xff0c;因此这种方法特别注重子问题之间的转移关系…

使用生成对抗网络增强网络入侵检测性能

文章目录前言一、GAN 模型介绍二、研究方法1.数据集选择与处理2.IDS 基线模型构建3. GAN 模型设计与样本生成4.生成样本质量评估三、实验评估四、总结前言 网络入侵检测系统&#xff08;Network Intrusion Detection System, NIDS&#xff09;在保护关键数字基础设施免受网络威…

VR森林经营模拟体验带动旅游经济发展

将VR森林经营模拟体验作为一种独特的旅游项目&#xff0c;正逐渐成为旅游市场的新热点。游客们无需长途跋涉前往深山老林&#xff0c;只需在旅游景区的VR体验中心&#xff0c;戴上VR设备&#xff0c;就能开启一场奇妙的森林之旅。在虚拟森林中&#xff0c;他们可以尽情探索&…

Vue2存量项目国际化改造踩坑

Vue2存量项目国际化改造踩坑 一、背景 在各类业务场景中&#xff0c;国际化作为非常重要的一部分已经有非常多成熟的方案&#xff0c;但对于一些存量项目则存在非常的改造成本&#xff0c;本文将分享一个的Vue2项目国际化改造方案&#xff0c;通过自定义Webpack插件自动提取中文…

硬件开发(1)—单片机(1)

1.单片机相关概念1.CPU&#xff1a;中央处理器&#xff0c;数据运算、指令处理&#xff0c;CPU性能越高&#xff0c;完成指令处理和数据运算的速度越快核心&#xff1a;指令解码执行数据运算处理2.MCU&#xff1a;微控制器&#xff0c;集成度比较高&#xff0c;将所有功能集成到…

Elasticsearch面试精讲 Day 4:集群发现与节点角色

【Elasticsearch面试精讲 Day 4】集群发现与节点角色 在“Elasticsearch面试精讲”系列的第四天&#xff0c;我们将深入探讨Elasticsearch分布式架构中的核心机制——集群发现&#xff08;Cluster Discovery&#xff09;与节点角色&#xff08;Node Roles&#xff09;。这是构…

微信小程序长按识别图片二维码

提示&#xff1a;二维码图片才能显示识别菜单1.第一种方法添加属性&#xff1a;show-menu-by-longpress添加属性&#xff1a;show-menu-by-longpress <image src"{{shop.wx_qrcode}}" mode"widthFix" show-menu-by-longpress></image>2.第二种…

智能化数据平台:AI 与大模型驱动的架构升级

在前面的文章中,我们探讨了 存算分离与云原生,以及 流批一体化计算架构 的演进趋势。这些演进解决了“算力与数据效率”的问题。但在今天,企业在数据平台上的需求已经从 存储与计算的统一,逐步走向 智能化与自动化。 尤其是在 AI 与大模型快速发展的背景下,数据平台正在发…

解锁 Vue 动画的终极指南:Vue Bits 实战进阶教程,让你的Vue动画比原生动画还丝滑,以及动画不生效解决方案。

一条 Splash Cursor 的 10 秒 Demo 视频曾创下 200 万 播放量&#xff0c;让 React Bits 风靡全球。如今&#xff0c;Vue 开发者终于迎来了官方移植版 —— Vue Bits。 在现代 Web 开发中&#xff0c;UI 动效已成为提升用户体验的关键因素。Vue Bits 作为 React Bits 的官方 Vu…

《微服务协作实战指南:构建全链路稳健性的防御体系》

在微服务架构从“技术尝鲜”迈向“规模化落地”的进程中&#xff0c;服务间的协作不再是简单的接口调用&#xff0c;而是涉及超时控制、事务一致性、依赖容错、配置同步等多维度的复杂博弈。那些潜藏于协作链路中的隐性Bug&#xff0c;往往不是单一服务的功能缺陷&#xff0c;而…

STM32F103C8T6的智能医疗药品存储柜系统设计与华为云实现

项目开发背景 随着现代医疗技术的快速发展&#xff0c;药品的安全存储与管理成为医疗质量控制中的重要环节。许多药品对存储环境的温湿度具有严格的要求&#xff0c;一旦超出允许范围&#xff0c;药品的理化性质可能发生改变&#xff0c;甚至失效&#xff0c;直接影响患者的用药…

python批量调用大模型API:多线程和异步协程

文章目录 多线程批量调用 基本原理 实现代码 代码解析 使用注意事项 异步协程实现批量调用 异步协程实现方式 异步实现的核心原理 多线程 vs 异步协程 选择建议 多线程批量调用 基本原理 多线程批量调用大模型API的核心思想是通过并发处理提高效率,主要原理包括: 并发请求:…

硬件开发1-51单片机1

一、嵌入式1、概念&#xff1a;以应用为中心&#xff0c;以计算机技术为基础&#xff0c;软硬件可裁剪的专用计算机系统以应用为中心&#xff1a;系统设计的起点是 “具体应用场景”&#xff0c;按照应用需求出发以计算机技术为基础&#xff1a; 硬件技术&#xff1a;嵌…

Redis核心数据类型解析——string篇

Redis的常见数据类型Redis 提供了 5 种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维⾮常重要&#xff0c;同时掌握每 种数据结构的常⻅命令&#xff0c;会在使⽤ Redis 的时候做到游刃有余。预备在正式介绍 5 种数据结构之前&#xff0c;了解⼀下 Redis 的⼀…

爬虫逆向--Day20Day21--扣JS逆向练习【案例4:深证信服务平台】

一、案例【深证信数据服务平台】案例地址链接&#xff1a;https://webapi.cninfo.com.cn/#/marketDataDate案例爬取链接&#xff1a;https://webapi.cninfo.com.cn/api/sysapi/p_sysapi10071.1、入口定位当进行入口定位时&#xff0c;我们首先需要进行查看响应、载荷、请求头是…

ExcelJS实现导入转换HTML展示(附源码可直接使用)

目录 简介 开始实践 难点 文件示例 效果预览 具体实现 安装 完整代码 总结 简介 在日常工作中&#xff0c;我们可能会遇到需要上传并展示 Excel 文件的需求&#xff0c;实现文件内容的在线预览。 这里给大家接收一个组件库exceljs&#xff0c;这个组件库进过实践发现…