muduo库TcpConnection模块详解——C++
muduo库中的TcpConnection
模块详解
TcpConnection
是muduo库中处理TCP连接的核心模块,负责管理单个TCP连接的生命周期、数据读写、状态转换以及事件回调。每个TCP连接对应一个TcpConnection
对象,其设计体现了高性能、线程安全和灵活回调的特点。
一、核心职责
- 连接生命周期管理
管理TCP连接的建立、活跃状态、关闭过程及销毁。 - 数据读写与缓冲
通过inputBuffer
和outputBuffer
处理数据的接收与发送,应对粘包/半包问题。 - 事件回调机制
提供用户可配置的回调函数(如消息到达、连接关闭、发送完成等)。 - 线程安全保证
确保所有操作在绑定的EventLoop
线程中执行,避免竞态条件。
二、关键数据结构与成员
1. 类定义概览
class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:// 连接状态枚举enum State { kConnecting, kConnected, kDisconnecting, kDisconnected };// 回调函数类型定义using MessageCallback = std::function<void(const TcpConnectionPtr&, Buffer*, Timestamp)>;using CloseCallback = std::function<void(const TcpConnectionPtr&)>;private:EventLoop* loop_; // 所属EventLoop(即IO线程)State state_; // 当前连接状态std::unique_ptr<Socket> socket_; // 管理的Socket对象std::unique_ptr<Channel> channel_; // 关联的Channel,用于事件监听Buffer inputBuffer_; // 接收数据缓冲区Buffer outputBuffer_; // 发送数据缓冲区MessageCallback messageCallback_; // 消息到达回调CloseCallback closeCallback_; // 连接关闭回调
};
2. 成员说明
loop_
指向绑定的EventLoop
,所有操作必须在该线程执行。state_
管理连接状态,确保状态转换的合法性(如不允许在已关闭的连接上发送数据)。socket_
和channel_
封装底层socket文件描述符及其事件监听,channel_
注册到loop_
中处理读写事件。inputBuffer_
和outputBuffer_
应用层缓冲区,用于暂存接收和待发送的数据。- 回调函数
用户通过setMessageCallback()
等接口设置自定义逻辑。
三、生命周期管理
1. 连接建立
- 创建时机
由TcpServer
或TcpClient
在连接建立时创建TcpConnection
对象。 - 初始化流程
- 设置socket为非阻塞模式。
- 绑定
Channel
到EventLoop
,注册可读事件。 - 状态设为
kConnecting
,随后通过connectEstablished()
转为kConnected
。
2. 连接关闭
- 主动关闭
用户调用shutdown()
,发送剩余数据后关闭写端(SHUT_WR
)。 - 被动关闭
收到FIN包(读返回0)时,触发handleClose()
。 - 状态转换
kConnected
→kDisconnecting
→kDisconnected
,最终调用closeCallback_
通知上层。
3. 对象销毁
- 使用
shared_ptr
管理生命周期,通过shared_from_this()
确保回调中对象存活。 - 连接关闭后,
TcpServer
或TcpClient
从连接列表中移除该对象的引用。
四、数据读写流程
1. 数据接收
-
可读事件处理
void TcpConnection::handleRead(Timestamp receiveTime) {ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);if (n > 0) {messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);} else if (n == 0) { // 对端关闭连接handleClose();} else { // 错误处理handleError();} }
-
用户处理逻辑
通过messageCallback_
将数据传递给用户,用户从inputBuffer_
解析完整消息。
2. 数据发送
-
发送入口
void TcpConnection::send(const std::string& message) {if (state_ == kConnected) {if (loop_->isInLoopThread()) {sendInLoop(message.data(), message.size());} else {loop_->runInLoop([this, msg = message] { sendInLoop(msg.data(), msg.size()); });}} }
-
实际发送逻辑
void TcpConnection::sendInLoop(const void* data, size_t len) {if (channel_->isWriting() && outputBuffer_.readableBytes() == 0) {// 直接尝试写入socketssize_t n = ::write(channel_->fd(), data, len);if (n < 0) { /* 错误处理 */ }if (static_cast<size_t>(n) < len) {// 剩余数据加入outputBuffer_并注册可写事件outputBuffer_.append(static_cast<const char*>(data)+n, len-n);channel_->enableWriting();}} else {// 数据直接追加到outputBuffer_outputBuffer_.append(data, len);if (!channel_->isWriting()) {channel_->enableWriting();}} }
-
可写事件处理
void TcpConnection::handleWrite() {ssize_t n = ::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes());if (n > 0) {outputBuffer_.retrieve(n);if (outputBuffer_.readableBytes() == 0) {channel_->disableWriting(); // 避免忙等待if (state_ == kDisconnecting) {shutdownInLoop(); // 关闭写端}}} }
五、状态管理与异常处理
1. 状态转换图
kConnecting → kConnected → kDisconnecting → kDisconnected↑_________________________|
- 关键转换点:
connectEstablished()
:kConnecting
→kConnected
shutdown()
:kConnected
→kDisconnecting
handleClose()
:kDisconnecting
→kDisconnected
2. 异常处理
- socket错误
handleError()
调用closeCallback_
并关闭连接。 - 对方意外断开
readFd()
返回0时触发handleClose()
。 - 发送失败处理
根据errno
判断是否为可恢复错误(如EAGAIN
),否则关闭连接。
六、线程安全机制
- 跨线程调用保护
所有非IO线程的操作通过loop_->runInLoop()
转移到IO线程执行。 - 智能指针管理
使用shared_from_this()
确保回调执行期间对象不被销毁。 - 状态变更原子性
状态state_
的修改仅在IO线程中进行,无需加锁。
七、高级功能
- TCP_NODELAY选项
通过setTcpNoDelay()
禁用Nagle算法,减少小数据包延迟。 - Keep-Alive机制
setKeepAlive()
启用TCP保活探测,检测死连接。 - 水位线控制
设置高水位回调(highWaterMarkCallback_
),防止发送缓冲区堆积。
八、典型使用示例
// 创建TcpServer并设置回调
TcpServer server(&loop, InetAddress(9876), "EchoServer");
server.setConnectionCallback([](const TcpConnectionPtr& conn) {if (conn->connected()) {conn->setTcpNoDelay(true); // 启用TCP_NODELAY}
});
server.setMessageCallback([](const TcpConnectionPtr& conn, Buffer* buf, Timestamp) {conn->send(buf->retrieveAllAsString()); // 回显数据
});
server.start();
loop.loop();
九、设计思想总结
- 资源封装
将socket、缓冲区、事件监听封装为对象,简化资源管理。 - 事件驱动
基于Reactor模式,通过事件回调实现异步非阻塞IO。 - 线程隔离
每个连接绑定到固定IO线程,避免锁竞争。 - 灵活扩展
用户可通过回调自定义协议处理逻辑(如HTTP、Redis协议)。
通过TcpConnection
模块,muduo库实现了高效、稳定的TCP连接管理,支撑了高性能服务器的开发需求。
相关文章:
muduo库TcpConnection模块详解——C++
muduo库中的TcpConnection模块详解 TcpConnection是muduo库中处理TCP连接的核心模块,负责管理单个TCP连接的生命周期、数据读写、状态转换以及事件回调。每个TCP连接对应一个TcpConnection对象,其设计体现了高性能、线程安全和灵活回调的特点。 一、核心…...
Node.js 源码架构详解
Node.js 的源码是一个庞大且复杂的项目,它主要由 C 和 JavaScript 构成。要完全理解每一部分需要大量的时间和精力。我会给你一个高层次的概述,并指出一些关键的目录和组件,帮助你开始探索。 Node.js 的核心架构 Node.js 的核心可以概括为以…...

全局异常处理:如何优雅地统一管理业务异常
在软件开发中,异常处理是保证系统健壮性的重要环节。一个良好的异常处理机制不仅能提高代码的可维护性,还能为使用者提供清晰的错误反馈。本文将介绍如何通过全局异常处理和业务异常统一处理来编写更加优雅的代码。 一、传统异常处理的痛点 1.1 典型问…...
分布式锁: Redis和ZooKeeper两种分布式锁对比
在分布式系统中,分布式锁是协调多节点共享资源访问的核心机制。Redis 和 ZooKeeper 是两种常用的分布式锁实现方案,但两者的设计理念、适用场景和优缺点存在显著差异。本文将从 一致性模型、性能、可靠性、实现原理 等维度进行对比,并提供技术…...

动态规划-LCR 166.珠宝的最大价值-力扣(LeetCode)
一、题目解析 frame二维矩阵中每个值代表珠宝的价值,现在从左上角开始拿珠宝,只能向右或向下拿珠宝,到达右下角时停止拿珠宝,要求拿的珠宝价值最大。 二、算法解析 1.状态表示 我们想要知道的是到达[i,j]为位置时的最大价值&am…...

JDBC实现模糊、动态与分页查询的详解
文章目录 一. 模糊查询1. Mysql的写法2. JDBC的实现 二. 动态条件查询1. 创建生成动态条件查询sql的方法2. 完整的动态条件查询类以及测试类 三. 分页查询1. 什么是分页查询?2. 分页查询的分类3. MySQL的实现4. JDBC实现4.1. 创建page页4.2. 分页的实现 本章来讲一下…...

域环境信息收集技术详解:从基础命令到实战应用
引言 在企业网络环境中,Active Directory (AD)域服务是微软提供的集中式目录服务,用于管理网络中的用户、计算机和其他资源。对于信息安全专业人员来说,熟练掌握域环境信息收集技术至关重要,无论是进行渗透测试、安全评估还是日常…...
nodejs特性解读
单线程和事件驱动架构 参考 程序员dd-事件驱动架构 it-老齐-事件驱动架构 总结...

【C++ Qt】布局管理器
每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 🤔绪论: 在Qt开发中,界面布局的合理设计是提升用户体验的关键。早期,开发者常采用绝对定位的方式摆放控件,即通…...

vscode用python开发maya联动调试设置
如何在VScode里编写Maya Python脚本_哔哩哔哩_bilibili1 包括1,maya的python全面在vscode支持,2,通过mayacode发送到maya,3同步调试 import maya.cmds as cmds 1、让 maya.cmds编译通过 下载Autodesk_Maya_2018_6_Update_DEVK…...

SLAM定位常用地图对比示例
序号 地图类型 概述 1 格栅地图 将现实环境栅格化,每一个栅格用 0 和 1 分别表示空闲和占据状态,初始化为未知状态 0.5 2 特征地图 以点、线、面等几何特征来描绘周围环境,将采集的信息进行筛选和提取得到关键几何特征 3 拓扑地图 将重要部分抽象为地图,使用简单的图形表示…...
Ubnutu ADB 无法识别设备的解决方法
1. 正确安装adb 下载地址 2. 检查 Linux 是否识别设备 lsusb通过上述指令,分别查询插入、断开设备的usb设备表,如下所示: # 插入设备 adbc:~$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 011:…...
前端-HTML元素
目录 HTML标签是什么? 什么是HTML元素? HTML元素有哪些分类方法? 什么是HTML头部元素 更换路径 注:本文以leetbook为基础 HTML标签是什么? HTML标签是HTML语言中最基本单位和重要组成部分 虽然它不区分大小写&a…...
dagster的etl实现
本文展示了如何使用Dagster框架实现一个动态ETL(Extract, Transform, Load)流程。通过定义多个操作(op),包括生成动态任务、处理单个任务、收集结果和汇总结果,构建了一个动态任务处理流程。generate_tasks…...

python的漫画网站管理系统
目录 技术栈介绍具体实现截图系统设计研究方法:设计步骤设计流程核…...

源码安装gperftools工具
源码安装gperftools工具 下载gperftools源码 https://github.com/gperftools/gperftools/releases/download/gperftools-2.16/gperftools-2.16.tar.gz 注:需要下载github上release版本,如果直接下载master分支上源码,将可能出现各种编译报错…...
QMK 宏(Macros)功能详解(实战部分)
QMK 宏(Macros)功能详解(实战部分) 一、宏的基本概念与作用 宏(Macros)是 QMK 固件中一项强大的功能,它允许您在按下单个按键时执行多个按键操作。通过宏,您可以: 输入常用短语或文本执行复杂的按键组合自动化重复性操作触发系统功能或快捷键🔔 安全提示:虽然可以…...

前端脚手架开发指南:提高开发效率的核心操作
前端脚手架通过自动化的方式可以提高开发效率并减少重复工作,而最强大的脚手架并不是现成的那些工具而是属于你自己团队量身定制的脚手架!本篇文章将带你了解脚手架开发的基本技巧,帮助你掌握如何构建适合自己需求的工具,并带着你…...

搜索引擎工作原理|倒排索引|query改写|CTR点击率预估|爬虫
写在前面 使用搜索引擎是我们经常做的事情,搜索引擎的实现原理。 什么是搜索引擎 搜索引擎是一种在线搜索工具,当用户在搜索框输入关键词时,搜索引擎就会将与该关键词相关的内容展示给用户。比较大型的搜索引擎有谷歌,百度&…...

Python实例题:Python自动工资条
目录 Python实例题 题目 python-automatic-payroll-slipPython 自动生成工资条脚本 代码解释 加载文件: 获取表头: 写入表头: 生成工资条: 保存文件: 运行思路 注意事项 Python实例题 题目 Python自动工资…...

Function Calling万字实战指南:打造高智能数据分析Agent平台
个人主页:Guiat 归属专栏:科学技术变革创新 文章目录 1. Function Calling:智能交互的新范式1.1 Function Calling 技术概述1.2 核心优势分析 2. 数据分析Agent平台架构设计2.1 系统架构概览2.2 核心组件解析2.2.1 函数注册中心2.2.2 Agent控…...
spark MySQL数据库配置
Spark 连接 MySQL 数据库的配置 要让 Spark 与 MySQL 数据库实现连接,需要进行以下配置步骤。下面为你提供详细的操作指南和示例代码: 1. 添加 MySQL JDBC 驱动依赖 你得把 MySQL 的 JDBC 驱动添加到 Spark 的类路径中。可以通过以下两种方式来完成&a…...
python四则运算计算器
python四则运算计算器 是谁说,python不好写计算器的,我亲自写个无ui的计算器功能,证明这是谣言 step1:C:\Users\wangrusheng\Downloads\num.txt 15 - 4 * 3 10 / 2(5 3) * 2 6 / 31/2 * 8 3/4 * 4 - 0.52.5 * (4 1.6) - 9 / 3-6 12 * (…...

线对板连接器的兼容性问题:为何老旧设计难以满足现代需求?
线对板连接器作为电子设备的核心纽带,正面临前所未有的兼容性挑战。某智能工厂升级生产线时发现,沿用十年的2.54毫米间距连接器,在接入新型工业相机时出现30%的信号丢包率,而切换至0.4毫米超密间距连接器后,数据传输速…...

AI517 AI本地部署 docker微调(失败)
本地部署AI 计划使用OLLAMA进行本地部署 修改DNS 访问github 刷新缓存 配置环境变量 OLLAMA安装成功 部署成功 计划使用docker进行微调 下载安装docker 虚拟化已开启 开启上面这些 准备下载ubuntu docker ragflow dify 用git去泡...

VR和眼动控制集群机器人的方法
西安建筑科技大学信息与控制工程学院雷小康老师团队联合西北工业大学航海学院彭星光老师团队,基于虚拟现实(VR)和眼动追踪技术实现了人-集群机器人高效、灵活的交互控制。相关研究论文“基于虚拟现实和眼动的人-集群机器人交互方法” 发表于信…...
python训练营打卡第26天
函数专题1:函数定义与参数 知识点回顾: 函数的定义变量作用域:局部变量和全局变量函数的参数类型:位置参数、默认参数、不定参数传递参数的手段:关键词参数传递参数的顺序:同时出现三种参数类型时 作业&…...

TiDB 中新 Hash Join 的设计与性能优化
原文来源: https://tidb.net/blog/11667c37 本文作者:徐飞 导读 在数据库管理系统(DBMS)中,连接操作(Join)是查询处理的核心环节之一,其性能直接影响到整个系统的响应速度和效率…...

1.共享内存(python共享内存实际案例,传输opencv frame)
主进程程序 send.py import cv2 import numpy as np from multiprocessing import shared_memory, resource_trackercap cv2.VideoCapture(0) if not cap.isOpened():print("无法打开 RTSP 流,请检查地址、网络连接或 GStreamer 配置。") else:# 创建共…...

网页常见水印实现方式
文章目录 1 明水印技术实现1.1 DOM覆盖方案1.2 Canvas动态渲染1.3 CSS伪元素方案2 暗水印技术解析2.1 空域LSB算法2.2 频域傅里叶变换3 防篡改机制设计3.1 MutationObserver防护3.2 Canvas指纹追踪4 前后端实现对比5 攻防博弈深度分析5.1 常见破解手段5.2 进阶防御策略6 选型近…...