[muduo] TcpConnection | 回调交互
第六章:TcpConnection
在前几章中,我们已经构建了Muduo网络库的基础。
-
我们理解
EventLoop
(第一章:EventLoop)是单线程的事件引擎,负责管理事件。 -
我们学习了
muduo::Thread
(第二章:Thread)如何帮助在专用线程中运行EventLoop
以实现并发。 -
我们看到了
Channel
(第三章:Channel)如何将特定的文件描述符(如套接字)连接到EventLoop
并保存该FD的事件回调。 -
我们了解了
Poller
(第四章:Poller)如何高效地等待多个Channel的事件 -
以及
TimerQueue
(第五章:TimerQueue)如何处理基于时间的事件。
现在我们将这些组件整合起来处理实际的网络通信。
-
当建立TCP连接时——无论是服务器接受的连接还是客户端发起的连接——都会获得一个准备好发送和接收数据的套接字文件描述符。
手动管理每个套接字的读写、缓冲和连接状态非常复杂。
这正是
muduo::net::TcpConnection
类的职责所在。
TcpConnection解决了什么问题?
假设服务器接受了一个新的客户端连接
。操作系统会提供一个全新的套接字文件描述符
。数据可能随时到达这个套接字。需要:
- 从套接字读取传入数据
- 缓冲传入数据直到形成完整消息
- 处理完整消息
- 向客户端发送返回数据
- 在网络繁忙时缓冲出站数据
- 优雅地处理错误和连接关闭
- 跟踪连接状态(连接中/已连接/断开中/已断开)
直接使用底层套接字调用并管理可能数千个连接的缓冲是项艰巨的任务。
TcpConnection
类为单个已建立的TCP连接提供了高级的面向对象抽象。
它封装了套接字文件描述符,处理底层I/O操作(读/写),管理输入输出缓冲区,并通过回调提供了清晰的接口供插入应用逻辑。
将TcpConnection
视为客户端的专属"会话管理器"。一旦客户端连接,就会创建TcpConnection
对象来处理与该特定客户端的所有通信,直到连接关闭
。
TcpConnection:会话管理器
muduo::net::TcpConnection
对象代表与对等端的一个活动连接。无论是连接到服务器的客户端,还是客户端连接远程服务器,都使用TcpConnection
对象。
以下是muduo::net::TcpConnection
的核心概念:
- 每连接专属:每个已建立的TCP连接对应一个
TcpConnection
对象 - 单EventLoop归属:与
Channel
或Poller
类似,TcpConnection
对象属于单个EventLoop
,其方法必须在该EventLoop
线程中调用 - 管理Socket和Channel:拥有底层
Socket
对象(封装文件描述符)和与该套接字FD关联的Channel
对象。Channel
将FD注册到EventLoop
的Poller
以监视读/写事件 - 输入输出缓冲区:包含
inputBuffer_
(muduo::net::Buffer
,后续章节详述)用于存储从套接字读取的输入数据,以及outputBuffer_
用于暂存尚未完全发送的输出数据 - 状态机:连接经历不同状态:
kConnecting
(建立时短暂存在)、kConnected
(准备就绪)、kDisconnecting
(本地关闭中)、kDisconnected
(已断开) - 回调机制:应用开发者通过回调函数与
TcpConnection
交互。通常通过创建它的TcpServer
或TcpClient
设置以下回调:
ConnectionCallback
:连接状态变化时触发MessageCallback
:新数据到达并读入inputBuffer_
时触发WriteCompleteCallback
:输出缓冲区排空后触发HighWaterMarkCallback
:输出缓冲区超过阈值时触发CloseCallback
:内部用于管理对象生命周期
使用TcpConnection:通过回调交互
通常不直接创建TcpConnection
对象
而是由TcpServer
(接受新连接时)或TcpClient
(连接服务器成功时)自动创建。
开发者主要通过设置回调函数与TcpConnection
交互。以下是muduo/net/Callbacks.h
中定义的回调类型:
#include <functional>
#include <memory>namespace muduo {
namespace net {class Buffer;
class TcpConnection;
class Timestamp;typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
typedef std::function<void (const TcpConnectionPtr&,Buffer*,Timestamp)> MessageCallback;
typedef std::function<void (const TcpConnectionPtr&)> WriteCompleteCallback;
typedef std::function<void (const TcpConnectionPtr&, size_t)> HighWaterMarkCallback;
typedef std::function<void (const TcpConnectionPtr&)> CloseCallback;} // namespace net
} // namespace muduo
主要用户接口方法:
class TcpConnection : noncopyable, public std::enable_shared_from_this<TcpConnection> {
public:void send(const void* message, int len);void send(const StringPiece& message);void send(Buffer* message);void shutdown();void forceClose();void forceCloseWithDelay(double seconds);void startRead();void stopRead();bool isReading() const;Buffer* inputBuffer();Buffer* outputBuffer();void setContext(const boost::any& context);const boost::any& getContext() const;boost::any* getMutableContext();void setConnectionCallback(const ConnectionCallback& cb);void setMessageCallback(const MessageCallback& cb);void setWriteCompleteCallback(const WriteCompleteCallback& cb);void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark);
};
典型回调使用示例:
void onConnection(const TcpConnectionPtr& conn) {if (conn->connected()) {LOG_INFO << "Connection UP: " << conn->name();conn->send("Hello!\n");} else {LOG_INFO << "Connection DOWN: " << conn->name();}
}void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) {LOG_INFO << "Received " << buf->readableBytes() << " bytes";conn->send(buf);
}void onWriteComplete(const TcpConnectionPtr& conn) {LOG_INFO << "Write complete";
}void onHighWaterMark(const TcpConnectionPtr& conn, size_t bytes) {LOG_INFO << "High water mark: " << bytes;conn->stopRead();
}
回调
回调就像点外卖时留电话号码:
你告诉外卖平台"餐到了就打电话通知我",而不是一直盯着手机看。
这里的电话号码就是回调函数,外卖平台就是调用者。
体现
onConnection
函数:
当网络连接状态变化时(比如连接成功或断开),系统会自动调用这个函数,就像外卖到了自动给你打电话。
onMessage
函数:
当收到网络消息时自动触发,相当于"有快递包裹到了就通知我"的设定。
onWriteComplete
函数:
当数据发送完成时自动执行,类似"外卖小哥离开后给我发短信确认"。
onHighWaterMark
函数:
当数据堆积过多时触发,相当于"快递柜快满了就提醒我取件"。
特点
- 预先写好处理函数(
回调函数
) - 系统在特定事件发生时自动调用(外卖到了)
- 不需要主动去查询状态(会通过回调函数打电话)
- 处理逻辑完全由你定义
这种机制避免了程序不断轮询检查状态,就像不用每隔5分钟就给外卖平台打电话问"餐到了没"。
TcpConnection内部机制
通过序列图展示数据接收流程:
核心内部方法实现逻辑:
- 构造函数:绑定套接字
FD
,创建Channel
,设置事件回调 connectEstablished
:完成连接建立
,启用读监控handleRead
:处理读事件,填充输入缓冲区,触发消息回调sendInLoop
:实现高效数据发送
,处理缓冲区管理handleWrite
:处理写事件,管理输出缓冲区handleClose
:处理连接关闭,触发相关回调
总结
功能 | 描述 | 优势 |
---|---|---|
每连接对象 | 代表单个TCP连接 | 提供高级会话管理接口 |
EventLoop归属 | 严格单线程操作 | 简化并发控制,无需锁机制 |
Socket & Channel | 封装套接字和事件通道 | 深度集成事件循环机制 |
双缓冲系统 | inputBuffer_存储输入,outputBuffer_管理输出 | 高效处理流量控制和不完整数据包 |
状态机 | 明确的状态迁移(kConnecting→kConnected→kDisconnecting→kDisconnected) | 清晰管理连接生命周期 |
回调体系 | 五类核心回调覆盖连接全生命周期 | 灵活对接业务逻辑 |
智能发送方法 | send()系列方法自动处理缓冲和流量控制 | 简化应用层开发 |
优雅关闭机制 | shutdown()保证数据完整性,forceClose()立即终止 | 满足不同场景需求 |
TcpConnection作为Muduo网络库的核心组件
通过封装底层套接字
操作、管理双缓冲
系统、维护状态机
,并结合事件循环
机制,为TCP连接管理提供了高效可靠的解决方案。
其回调驱动
的设计模式使得业务逻辑与网络层完美解耦,是构建高性能网络应用的基石。
第七章:Buffer将深入解析Muduo的缓冲区实现机制。