目录
[一、 TcpConnection.h](#一、 TcpConnection.h)
[1. 整体定位](#1. 整体定位)
[2. 类的关键继承](#2. 类的关键继承)
[3. 连接状态机](#3. 连接状态机)
[4. 核心成员变量](#4. 核心成员变量)
[5. 核心对外接口](#5. 核心对外接口)
[1. 发送数据](#1. 发送数据)
[2. 关闭连接](#2. 关闭连接)
[3. 地址 / 状态](#3. 地址 / 状态)
[4. 上下文](#4. 上下文)
[5. 开关读](#5. 开关读)
[6. 内部核心函数](#6. 内部核心函数)
[1. connectEstablished()](#1. connectEstablished())
[2. connectDestroyed()](#2. connectDestroyed())
[3. 四大事件处理函数](#3. 四大事件处理函数)
[7. 工作流程](#7. 工作流程)
[8. 为什么要用 Buffer?](#8. 为什么要用 Buffer?)
[9. 为什么要用 shared_from_this?](#9. 为什么要用 shared_from_this?)
[二、 TcpConnection.cc](#二、 TcpConnection.cc)
[1. 整体定位](#1. 整体定位)
[2. 默认回调](#2. 默认回调)
[3. 构造函数](#3. 构造函数)
[4. 连接建立:connectEstablished ()](#4. 连接建立:connectEstablished ())
[5. 接收数据:handleRead ()](#5. 接收数据:handleRead ())
[6. 发送数据:send () → sendInLoop ()](#6. 发送数据:send () → sendInLoop ())
[1. send () 接口](#1. send () 接口)
[2. sendInLoop ()](#2. sendInLoop ())
[7. handleWrite ()](#7. handleWrite ())
[8. 关闭连接](#8. 关闭连接)
[1. 优雅关闭:shutdown ()](#1. 优雅关闭:shutdown ())
[2. 强制关闭:forceClose ()](#2. 强制关闭:forceClose ())
[9. handleClose ()](#9. handleClose ())
[10. 状态机](#10. 状态机)
[11. shared_from_this () 到底有什么用?](#11. shared_from_this () 到底有什么用?)
[12. 整个 TcpConnection 工作流程](#12. 整个 TcpConnection 工作流程)
一、 TcpConnection.h
先贴出完整代码,再逐部分解释:
cpp
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// 本源代码使用 BSD 许可证
// 可在 License 文件中找到详细条款
// 作者:陈硕 (chenshuo at chenshuo dot com)
//
// 这是一个公共头文件,仅允许包含公共头文件
#ifndef MUDUO_NET_TCPCONNECTION_H
#define MUDUO_NET_TCPCONNECTION_H
#include "muduo/base/noncopyable.h"
#include "muduo/base/StringPiece.h"
#include "muduo/base/Types.h"
#include "muduo/net/Callbacks.h"
#include "muduo/net/Buffer.h"
#include "muduo/net/InetAddress.h"
#include <memory>
#include <boost/any.hpp>
// tcp_info 结构体定义在 <netinet/tcp.h> 中
struct tcp_info;
namespace muduo
{
namespace net
{
class Channel;
class EventLoop;
class Socket;
///
/// TCP 连接类,服务端和客户端均可使用
///
/// 这是接口类,不对外暴露过多内部实现细节
/// 管理一个已建立的 TCP 连接的生命周期、数据收发、事件处理
class TcpConnection : noncopyable,
public std::enable_shared_from_this<TcpConnection>
{
public:
/// 通过已连接的 sockfd 构造 TcpConnection
///
/// 用户不应该直接创建该对象,由 TcpServer 自动创建
TcpConnection(EventLoop* loop,
const string& name,
int sockfd,
const InetAddress& localAddr,
const InetAddress& peerAddr);
~TcpConnection();
// 获取所属事件循环
EventLoop* getLoop() const { return loop_; }
// 获取连接名称
const string& name() const { return name_; }
// 获取本地地址
const InetAddress& localAddress() const { return localAddr_; }
// 获取对端地址
const InetAddress& peerAddress() const { return peerAddr_; }
// 判断是否已连接
bool connected() const { return state_ == kConnected; }
// 判断是否已断开
bool disconnected() const { return state_ == kDisconnected; }
// 获取 TCP 连接信息(tcp_info),成功返回 true
bool getTcpInfo(struct tcp_info*) const;
// 获取 TCP 连接信息字符串
string getTcpInfoString() const;
/// 发送数据接口(线程安全)
// void send(string&& message); // C++11
void send(const void* message, int len);
void send(const StringPiece& message);
// void send(Buffer&& message); // C++11
void send(Buffer* message); // 交换缓冲区数据,高效发送
/// 关闭写端(半关闭),非线程安全,不能并发调用
void shutdown();
// void shutdownAndForceCloseAfter(double seconds); // 非线程安全
/// 强制关闭连接
void forceClose();
/// 延迟指定秒数后强制关闭连接
void forceCloseWithDelay(double seconds);
/// 设置是否开启 TCP_NODELAY(禁用 Nagle 算法)
void setTcpNoDelay(bool on);
/// 开始监听读事件
void startRead();
/// 停止监听读事件
void stopRead();
/// 是否正在读取(非线程安全,可能与 start/stopReadInLoop 竞争)
bool isReading() const { return reading_; };
/// 设置用户自定义上下文(可存储任意类型数据)
void setContext(const boost::any& context)
{ context_ = context; }
/// 获取只读上下文
const boost::any& getContext() const
{ return context_; }
/// 获取可修改的上下文指针
boost::any* getMutableContext()
{ return &context_; }
/// 设置各类回调函数
// 连接建立/断开回调
void setConnectionCallback(const ConnectionCallback& cb)
{ connectionCallback_ = cb; }
// 消息到达回调
void setMessageCallback(const MessageCallback& cb)
{ messageCallback_ = cb; }
// 写完成回调(数据全部发送到内核缓冲区)
void setWriteCompleteCallback(const WriteCompleteCallback& cb)
{ writeCompleteCallback_ = cb; }
// 高水位回调(输出缓冲区超过阈值)+ 水位阈值
void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark)
{ highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; }
/// 高级接口
// 获取输入缓冲区(接收数据)
Buffer* inputBuffer()
{ return &inputBuffer_; }
// 获取输出缓冲区(待发送数据)
Buffer* outputBuffer()
{ return &outputBuffer_; }
/// 仅供内部使用
// 设置关闭回调(供 TcpServer 移除连接使用)
void setCloseCallback(const CloseCallback& cb)
{ closeCallback_ = cb; }
// 连接建立完成时调用(TcpServer 接受新连接后调用,仅调用一次)
void connectEstablished();
// 连接销毁时调用(TcpServer 从映射表移除后调用,仅调用一次)
void connectDestroyed();
private:
/// TCP 连接状态枚举
enum StateE {
kDisconnected, // 已断开
kConnecting, // 连接中
kConnected, // 已连接
kDisconnecting // 断开中
};
/// 事件处理函数
void handleRead(Timestamp receiveTime); // 处理读事件
void handleWrite(); // 处理写事件
void handleClose(); // 处理关闭事件
void handleError(); // 处理错误事件
/// IO 线程内执行发送
// void sendInLoop(string&& message);
void sendInLoop(const StringPiece& message);
void sendInLoop(const void* message, size_t len);
/// IO 线程内执行关闭
void shutdownInLoop();
// void shutdownAndForceCloseInLoop(double seconds);
void forceCloseInLoop();
/// 设置连接状态
void setState(StateE s) { state_ = s; }
/// 将状态转为字符串(日志打印用)
const char* stateToString() const;
/// IO 线程内启停读
void startReadInLoop();
void stopReadInLoop();
EventLoop* loop_; // 所属的事件循环(IO 线程)
const string name_; // 连接名称
StateE state_; // FIXME: 使用原子变量保证线程安全
bool reading_; // 是否正在监听读事件
// 不向用户暴露的内部成员
std::unique_ptr<Socket> socket_; // 管理连接 socket
std::unique_ptr<Channel> channel_; // 管理连接 fd 的事件通道
const InetAddress localAddr_; // 本地地址
const InetAddress peerAddr_; // 对端地址
/// 各类回调函数
ConnectionCallback connectionCallback_; // 连接状态变化回调
MessageCallback messageCallback_; // 消息到达回调
WriteCompleteCallback writeCompleteCallback_; // 数据发送完成回调
HighWaterMarkCallback highWaterMarkCallback_; // 高水位回调
CloseCallback closeCallback_; // 连接关闭回调
size_t highWaterMark_; // 高水位阈值
Buffer inputBuffer_; // 输入缓冲区(接收来自对端的数据)
Buffer outputBuffer_; // 输出缓冲区(待发送给对端的数据)
boost::any context_; // 用户自定义上下文(可存储任意类型)
// FIXME: 可扩展字段
// 创建时间、最后接收时间、接收字节数、发送字节数
};
/// TcpConnection 智能指针(使用 shared_ptr 管理生命周期)
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_TCPCONNECTION_H
1. 整体定位
TcpConnection 代表一条已经建立的 TCP 连接
- 封装了
fd+Channel+EventLoop - 管理读缓冲区、写缓冲区
- 处理
read/write/close/error事件 - 提供
send()/shutdown()/forceClose()接口 - 支持自定义上下文(boost::any) 绑定业务数据
- 采用
shared_from_this管理生命周期,安全不崩溃
它是 Muduo 网络编程中,用户最常打交道的类。
2. 类的关键继承
cpp
class TcpConnection : noncopyable,
public std::enable_shared_from_this<TcpConnection>
1. noncopyable
- 一条连接不能被拷贝,符合现实逻辑。
2. enable_shared_from_this
- 能安全地获取
shared_ptr<TcpConnection> - 防止连接在回调执行中被销毁导致崩溃
- Muduo 连接安全的核心保障
3. 连接状态机
cpp
enum StateE {
kDisconnected, // 已断开
kConnecting, // 连接中
kConnected, // 已连接
kDisconnecting // 正在关闭
};
所有操作都必须根据状态判断是否合法,避免错误关闭 / 发送。
4. 核心成员变量
cpp
EventLoop* loop_; // 所属IO线程(one loop per thread)
const string name_; // 连接名称
StateE state_; // 连接状态
bool reading_; // 是否正在监听读事件
std::unique_ptr<Socket> socket_; // 套接字
std::unique_ptr<Channel> channel_; // 事件分发器
InetAddress localAddr_; // 本地地址
InetAddress peerAddr_; // 对端地址
// 三大核心回调
ConnectionCallback connectionCallback_; // 连接建立/断开
MessageCallback messageCallback_; // 收到消息
WriteCompleteCallback writeCompleteCallback_; // 发送完成
Buffer inputBuffer_; // 读缓冲(内核→用户)
Buffer outputBuffer_; // 写缓冲(用户→内核)
boost::any context_; // 上下文(绑定用户数据)
5. 核心对外接口
1. 发送数据
cpp
void send(const StringPiece& message);
void send(Buffer* message);
- 线程安全
- 数据先放入
outputBuffer_ - 由
handleWrite()真正发送到内核
2. 关闭连接
cpp
void shutdown(); // 关闭写端,优雅关闭
void forceClose(); // 强制关闭
3. 地址 / 状态
cpp
const InetAddress& peerAddress();
bool connected();
bool disconnected();
4. 上下文
cpp
void setContext(const boost::any& context);
const boost::any& getContext() const;
可以绑定任何类型数据(如会话、用户对象、协议状态机)。
5. 开关读
cpp
void startRead();
void stopRead();
用于流量控制、暂停读取。
6. 内部核心函数
1. connectEstablished()
- 连接建立完成后调用
- 初始化 channel,开始监听读事件
- 调用
connectionCallback_(true)
2. connectDestroyed()
- 连接彻底销毁时调用
- 最后清理工作
3. 四大事件处理函数
cpp
void handleRead(Timestamp receiveTime); // 可读
void handleWrite(); // 可写
void handleClose(); // 对端关闭
void handleError(); // 出错
这些是 Reactor 模型真正干活的地方。
7. 工作流程
cpp
accept → TcpConnection 创建 → connectEstablished
→ 监听读事件
→ handleRead 读取数据 → messageCallback 交给用户
→ 用户 send → 数据放入 outputBuffer
→ handleWrite 发送数据 → writeCompleteCallback
→ 对端关闭 → handleClose → 连接销毁
8. 为什么要用 Buffer?
inputBuffer_
- 处理粘包
- 处理不完全读
- 交给用户的是完整缓冲区
outputBuffer_
- 处理无法一次发送完的数据
- 实现非阻塞发送
- 避免数据丢失
9. 为什么要用 shared_from_this?
回调执行时,连接可能正在被关闭 如果不用 shared_ptr 持有连接,回调执行到一半,连接被销毁,程序直接崩溃。
shared_from_this() 保证:只要回调还在,连接就不会死
二、 TcpConnection.cc
先贴出完整代码,再逐部分解释:
cpp
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// 本源代码使用 BSD 许可证
// 可在 License 文件中找到详细条款
// 作者:陈硕 (chenshuo at chenshuo dot com)
#include "muduo/net/TcpConnection.h"
#include "muduo/base/Logging.h"
#include "muduo/base/WeakCallback.h"
#include "muduo/net/Channel.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/Socket.h"
#include "muduo/net/SocketsOps.h"
#include <errno.h>
using namespace muduo;
using namespace muduo::net;
// 默认连接回调:仅打印连接建立/断开日志
void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn)
{
LOG_TRACE << conn->localAddress().toIpPort() << " -> "
<< conn->peerAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
// 不主动调用 forceClose,有些用户只需要注册消息回调
}
// 默认消息回调:直接丢弃收到的数据
void muduo::net::defaultMessageCallback(const TcpConnectionPtr&,
Buffer* buf,
Timestamp)
{
buf->retrieveAll();
}
// 构造函数:初始化 TCP 连接
TcpConnection::TcpConnection(EventLoop* loop,
const string& nameArg,
int sockfd,
const InetAddress& localAddr,
const InetAddress& peerAddr)
: loop_(CHECK_NOTNULL(loop)),
name_(nameArg),
state_(kConnecting), // 初始状态:连接中
reading_(true), // 初始开启读
socket_(new Socket(sockfd)),
channel_(new Channel(loop, sockfd)),
localAddr_(localAddr),
peerAddr_(peerAddr),
highWaterMark_(64*1024*1024) // 默认高水位 64MB
{
// 设置 channel 各类事件回调
channel_->setReadCallback(
std::bind(&TcpConnection::handleRead, this, _1));
channel_->setWriteCallback(
std::bind(&TcpConnection::handleWrite, this));
channel_->setCloseCallback(
std::bind(&TcpConnection::handleClose, this));
channel_->setErrorCallback(
std::bind(&TcpConnection::handleError, this));
LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this
<< " fd=" << sockfd;
// 默认开启 TCP keep-alive
socket_->setKeepAlive(true);
}
// 析构函数
TcpConnection::~TcpConnection()
{
LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this
<< " fd=" << channel_->fd()
<< " state=" << stateToString();
assert(state_ == kDisconnected);
}
// 获取 TCP 连接信息(tcp_info)
bool TcpConnection::getTcpInfo(struct tcp_info* tcpi) const
{
return socket_->getTcpInfo(tcpi);
}
// 获取 TCP 信息字符串
string TcpConnection::getTcpInfoString() const
{
char buf[1024];
buf[0] = '\0';
socket_->getTcpInfoString(buf, sizeof buf);
return buf;
}
// 发送数据:void* 版本
void TcpConnection::send(const void* data, int len)
{
send(StringPiece(static_cast<const char*>(data), len));
}
// 发送数据:StringPiece 版本(线程安全)
void TcpConnection::send(const StringPiece& message)
{
if (state_ == kConnected)
{
if (loop_->isInLoopThread())
{
// 在 IO 线程,直接发送
sendInLoop(message);
}
else
{
// 跨线程,投递到 IO 线程执行
void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop;
loop_->runInLoop(
std::bind(fp,
this,
message.as_string()));
}
}
}
// 发送数据:Buffer 版本
void TcpConnection::send(Buffer* buf)
{
if (state_ == kConnected)
{
if (loop_->isInLoopThread())
{
sendInLoop(buf->peek(), buf->readableBytes());
buf->retrieveAll();
}
else
{
void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop;
loop_->runInLoop(
std::bind(fp,
this,
buf->retrieveAllAsString()));
}
}
}
// IO 线程内发送:StringPiece
void TcpConnection::sendInLoop(const StringPiece& message)
{
sendInLoop(message.data(), message.size());
}
// IO 线程内真正执行发送(核心发送逻辑)
void TcpConnection::sendInLoop(const void* data, size_t len)
{
loop_->assertInLoopThread();
ssize_t nwrote = 0;
size_t remaining = len;
bool faultError = false;
// 连接已断开,放弃发送
if (state_ == kDisconnected)
{
LOG_WARN << "disconnected, give up writing";
return;
}
// 如果输出队列为空,尝试直接写
if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0)
{
nwrote = sockets::write(channel_->fd(), data, len);
if (nwrote >= 0)
{
remaining = len - nwrote;
// 全部发送完成,触发写完成回调
if (remaining == 0 && writeCompleteCallback_)
{
loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this()));
}
}
else // 写入出错
{
nwrote = 0;
if (errno != EWOULDBLOCK)
{
LOG_SYSERR << "TcpConnection::sendInLoop";
if (errno == EPIPE || errno == ECONNRESET)
{
faultError = true;
}
}
}
}
assert(remaining <= len);
// 还有数据未发送,加入输出缓冲区
if (!faultError && remaining > 0)
{
size_t oldLen = outputBuffer_.readableBytes();
// 超过高水位,触发回调
if (oldLen + remaining >= highWaterMark_
&& oldLen < highWaterMark_
&& highWaterMarkCallback_)
{
loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining));
}
// 追加到输出缓冲区
outputBuffer_.append(static_cast<const char*>(data)+nwrote, remaining);
// 注册写事件,等待内核可写
if (!channel_->isWriting())
{
channel_->enableWriting();
}
}
}
// 关闭写端(半关闭)
void TcpConnection::shutdown()
{
if (state_ == kConnected)
{
setState(kDisconnecting);
loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
}
}
// IO 线程内执行 shutdown
void TcpConnection::shutdownInLoop()
{
loop_->assertInLoopThread();
if (!channel_->isWriting())
{
// 没有正在写的数据,关闭写方向
socket_->shutdownWrite();
}
}
// 强制关闭连接
void TcpConnection::forceClose()
{
if (state_ == kConnected || state_ == kDisconnecting)
{
setState(kDisconnecting);
loop_->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this()));
}
}
// 延迟指定时间后强制关闭
void TcpConnection::forceCloseWithDelay(double seconds)
{
if (state_ == kConnected || state_ == kDisconnecting)
{
setState(kDisconnecting);
loop_->runAfter(
seconds,
makeWeakCallback(shared_from_this(),
&TcpConnection::forceClose));
}
}
// IO 线程内强制关闭
void TcpConnection::forceCloseInLoop()
{
loop_->assertInLoopThread();
if (state_ == kConnected || state_ == kDisconnecting)
{
handleClose();
}
}
// 将连接状态转为字符串(日志用)
const char* TcpConnection::stateToString() const
{
switch (state_)
{
case kDisconnected:
return "kDisconnected";
case kConnecting:
return "kConnecting";
case kConnected:
return "kConnected";
case kDisconnecting:
return "kDisconnecting";
default:
return "unknown state";
}
}
// 设置 TCP_NODELAY(禁用 Nagle 算法)
void TcpConnection::setTcpNoDelay(bool on)
{
socket_->setTcpNoDelay(on);
}
// 开始读(线程安全)
void TcpConnection::startRead()
{
loop_->runInLoop(std::bind(&TcpConnection::startReadInLoop, this));
}
// IO 线程内开启读事件
void TcpConnection::startReadInLoop()
{
loop_->assertInLoopThread();
if (!reading_ || !channel_->isReading())
{
channel_->enableReading();
reading_ = true;
}
}
// 停止读(线程安全)
void TcpConnection::stopRead()
{
loop_->runInLoop(std::bind(&TcpConnection::stopReadInLoop, this));
}
// IO 线程内关闭读事件
void TcpConnection::stopReadInLoop()
{
loop_->assertInLoopThread();
if (reading_ || channel_->isReading())
{
channel_->disableReading();
reading_ = false;
}
}
// 连接建立完成(由 TcpServer 调用)
void TcpConnection::connectEstablished()
{
loop_->assertInLoopThread();
assert(state_ == kConnecting);
setState(kConnected);
// 绑定 shared_ptr 防止连接在回调中被销毁
channel_->tie(shared_from_this());
channel_->enableReading();
// 触发连接回调
connectionCallback_(shared_from_this());
}
// 连接销毁(从 TcpServer 移除后调用)
void TcpConnection::connectDestroyed()
{
loop_->assertInLoopThread();
if (state_ == kConnected)
{
setState(kDisconnected);
channel_->disableAll();
connectionCallback_(shared_from_this());
}
channel_->remove();
}
// 处理读事件:数据到达
void TcpConnection::handleRead(Timestamp receiveTime)
{
loop_->assertInLoopThread();
int savedErrno = 0;
// 从 fd 读取数据到 inputBuffer
ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
if (n > 0)
{
// 有数据,触发消息回调
messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
}
else if (n == 0)
{
// 对端关闭连接
handleClose();
}
else
{
// 读取出错
errno = savedErrno;
LOG_SYSERR << "TcpConnection::handleRead";
handleError();
}
}
// 处理写事件:内核缓冲区可写
void TcpConnection::handleWrite()
{
loop_->assertInLoopThread();
if (channel_->isWriting())
{
// 把输出缓冲区数据写入 socket
ssize_t n = sockets::write(channel_->fd(),
outputBuffer_.peek(),
outputBuffer_.readableBytes());
if (n > 0)
{
outputBuffer_.retrieve(n);
// 数据全部发送完成
if (outputBuffer_.readableBytes() == 0)
{
channel_->disableWriting();
// 触发写完成回调
if (writeCompleteCallback_)
{
loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this()));
}
// 如果正在关闭,执行 shutdown
if (state_ == kDisconnecting)
{
shutdownInLoop();
}
}
}
else
{
LOG_SYSERR << "TcpConnection::handleWrite";
}
}
else
{
LOG_TRACE << "Connection fd = " << channel_->fd()
<< " is down, no more writing";
}
}
// 处理连接关闭
void TcpConnection::handleClose()
{
loop_->assertInLoopThread();
LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString();
assert(state_ == kConnected || state_ == kDisconnecting);
setState(kDisconnected);
channel_->disableAll();
TcpConnectionPtr guardThis(shared_from_this());
connectionCallback_(guardThis);
// 通知 TcpServer 移除该连接(必须最后调用)
closeCallback_(guardThis);
}
// 处理 socket 错误
void TcpConnection::handleError()
{
int err = sockets::getSocketError(channel_->fd());
LOG_ERROR << "TcpConnection::handleError [" << name_
<< "] - SO_ERROR = " << err << " " << strerror_tl(err);
}
1. 整体定位
一个 TcpConnection = 一条 TCP 连接它管理:
- 套接字(Socket)
- 事件(Channel)
- 所属 IO 线程(EventLoop)
- 输入 / 输出缓冲区(inputBuffer /outputBuffer)
- 连接状态(状态机)
- 各种回调(连接、消息、写完成、关闭)
所有网络数据收发,最终都落到这里。
2. 默认回调
cpp
void defaultConnectionCallback(...)
{
打印连接上下线日志
}
void defaultMessageCallback(...)
{
清空缓冲区(什么也不处理)
}
作用:避免用户没注册回调时程序崩溃。
3. 构造函数
cpp
TcpConnection::TcpConnection(EventLoop* loop, ...)
: loop_(loop),
state_(kConnecting), // 初始状态:连接中
socket_(new Socket(sockfd)),
channel_(new Channel(loop, sockfd))
{
// 绑定 channel 四大事件
channel_->setReadCallback( handleRead );
channel_->setWriteCallback( handleWrite );
channel_->setCloseCallback( handleClose );
channel_->setErrorCallback( handleError );
socket_->setKeepAlive(true);
}
关键点:
- channel 绑定了 fd 的所有事件
- 连接刚创建时状态是 kConnecting
- 开启 TCP keep-alive
4. 连接建立:connectEstablished ()
cpp
void TcpConnection::connectEstablished()
{
setState(kConnected); // 状态变为已连接
channel_->tie(shared_from_this()); // 绑定 shared_ptr(防止崩溃)
channel_->enableReading(); // 开始监听读事件
connectionCallback_(shared_from_this()); // 通知用户:连接上来了
}
这是 TcpServer accept 后必须调用的函数。
5. 接收数据:handleRead ()
cpp
void TcpConnection::handleRead(Timestamp receiveTime)
{
// 从 fd 读到 inputBuffer
ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
if (n > 0) {
// 读到数据 → 交给用户回调
messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
}
else if (n == 0) {
// 对端关闭 → handleClose
handleClose();
}
else {
handleError();
}
}
为什么要用 inputBuffer?
- 自动处理 TCP 粘包
- 自动处理 多次 read
- 用户只需要从 buffer 里取数据即可
6. 发送数据:send () → sendInLoop ()
1. send () 接口
cpp
void TcpConnection::send(const StringPiece& message)
{
if (state_ == kConnected)
{
if (loop_->isInLoopThread()) {
sendInLoop(message); // 自己线程,直接发
} else {
loop_->runInLoop( bind( sendInLoop, this, message ) );
}
}
}
**所有 send 最终都会跑到 IO 线程执行 sendInLoop ()**保证线程安全。
2. sendInLoop ()
cpp
void TcpConnection::sendInLoop(...)
{
// 第一步:如果输出缓冲区为空,尝试直接 write
if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0)
{
nwrote = sockets::write(fd, data, len);
}
// 第二步:如果没发完(EWOULDBLOCK)
if (remaining > 0)
{
outputBuffer_.append(...); // 剩下的数据放入输出缓冲区
channel_->enableWriting(); // 等待可写事件
}
}
发送流程总结:
- 能发就直接发
- 发不完 → 放进 outputBuffer
- 等待 Poller 通知可写
- 由 handleWrite () 继续发送
这就是非阻塞 IO 标准发送模型。
7. handleWrite ()
cpp
void TcpConnection::handleWrite()
{
// 把 outputBuffer 数据写出去
ssize_t n = sockets::write(fd, outputBuffer_.peek(), ...);
outputBuffer_.retrieve(n);
// 发完了
if (outputBuffer_.readableBytes() == 0)
{
channel_->disableWriting();
writeCompleteCallback_(); // 通知用户:发送完毕
}
}
8. 关闭连接
1. 优雅关闭:shutdown ()
cpp
void TcpConnection::shutdown()
{
setState(kDisconnecting);
loop_->runInLoop( shutdownInLoop );
}
void TcpConnection::shutdownInLoop()
{
if (!channel_->isWriting()) {
socket_->shutdownWrite(); // 关闭写端
}
}
等发送完缓冲区数据再关闭,不会丢数据。
2. 强制关闭:forceClose ()
cpp
void TcpConnection::forceClose()
{
loop_->queueInLoop( bind( forceCloseInLoop, shared_from_this() ) );
}
void TcpConnection::forceCloseInLoop()
{
handleClose();
}
9. handleClose ()
cpp
void TcpConnection::handleClose()
{
setState(kDisconnected);
channel_->disableAll();
TcpConnectionPtr guardThis(shared_from_this());
connectionCallback_(guardThis); // 通知用户:连接断开
closeCallback_(guardThis); // 通知 TcpServer 移除连接
}
guardThis 非常重要:保证连接在回调期间不被销毁。
10. 状态机
cpp
enum StateE {
kDisconnected,
kConnecting,
kConnected,
kDisconnecting
};
- send () 必须在 kConnected
- shutdown () 必须在 kConnected
- close () 可以在 kConnected /kDisconnecting
防止非法操作导致崩溃。
11. shared_from_this () 到底有什么用?
作用:防止回调执行到一半,连接被销毁导致崩溃。
例如:
- 回调里关闭连接
- 连接销毁了
- 回调还在执行
- 程序崩溃
shared_from_this() 会让 shared_ptr 计数 + 1只要回调还在,连接就不会死。
12. 整个 TcpConnection 工作流程
接收数据
cpp
channel 可读 → handleRead → 读到 inputBuffer → messageCallback
发送数据
cpp
用户 send → sendInLoop → 直接写 / 放入缓冲区 → 等待可写事件 → handleWrite 发送
关闭
cpp
对端关闭 / 主动关闭 → handleClose → 状态改为kDisconnected → 通知用户与TcpServer