解析muduo源码之 TcpConnection.h & TcpConnection.cc

目录

[一、 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();    // 等待可写事件
  }
}

发送流程总结:

  1. 能发就直接发
  2. 发不完 → 放进 outputBuffer
  3. 等待 Poller 通知可写
  4. 由 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
相关推荐
小义_3 小时前
随笔 1(Linux)
linux·运维·服务器·网络·云原生·红帽
进击的雷神3 小时前
主办方过滤、展位号模糊提取、多层级官网爬取、缅文编码解码——缅甸塑料展爬虫四大技术难关攻克纪实
网络·爬虫·python
上海云盾-小余3 小时前
CC 攻击与 DDoS 联动防护:如何构建一体化流量清洗架构
网络·安全·游戏·架构·ddos
向往着的青绿色3 小时前
雷池(SafeLine)社区版免费部署教程|从环境检查到防护实操全流程
网络·计算机网络·nginx·网络安全·容器·网络攻击模型·信息与通信
Larry_Yanan3 小时前
Qt网络开发之基于 QWebEngine 实现简易内嵌浏览器
linux·开发语言·网络·c++·笔记·qt·学习
AI+程序员在路上4 小时前
CAN 总线与 Linux SocketCAN C 语言测试程序
linux·c语言·网络
二进制person5 小时前
JavaEE初阶 --网络初识
运维·服务器·网络
李&@杰5 小时前
《中小型企业网络完整项目方案(拓扑+配置+说明+验收清单)》
网络
su1ka1115 小时前
计算机三级网络技术速记
网络