C++开发:rest_rpc连接Connection 类

    在一个RPC框架或网络库中,Connection 类代表了一个客户端与服务器之间的单个连接,并且负责管理该连接上的所有通信活动。

成员变量

  tcp::socket socket_;
#ifdef CINATRA_ENABLE_SSL
  std::unique_ptr<asio::ssl::stream<asio::ip::tcp::socket &>> ssl_stream_ =
      nullptr;
#endif
  bool has_shake_ = false;
  char head_[HEAD_LEN];
  std::vector<char> body_;
  std::uint64_t req_id_;
  request_type req_type_;

  rpc_header header_;

  uint32_t write_size_ = 0;

  asio::steady_timer timer_;
  std::size_t timeout_seconds_;
  int64_t conn_id_ = 0;
  bool has_closed_;

  std::deque<message_type> write_queue_;
  std::function<void(std::string, std::string, std::weak_ptr<connection>)>
      callback_;
  std::function<void(std::shared_ptr<connection>, std::string)> *on_net_err_ =
      nullptr;
  router &router_;
  nonstd::any user_data_;
  bool delay_ = false;  成员变量

1. 网络通信核心变量

tcp::socket socket_

  • 类型asio::ip::tcp::socket

  • 作用: 基础TCP套接字,处理所有网络IO操作

  • 特点:

    • 绑定到io_service执行上下文

    • 生命周期与connection对象一致

    • 提供异步读写接口

SSL相关变量

#ifdef CINATRA_ENABLE_SSL
std::unique_ptr<asio::ssl::stream<asio::ip::tcp::socket &>> ssl_stream_ = nullptr;
#endif
bool has_shake_ = false;
  • ssl_stream_:

    • 类型: SSL流对象的智能指针

    • 作用: 包装普通socket提供SSL/TLS加密通信

    • 特点: 条件编译,仅在开启SSL时存在

  • has_shake_:

    • 类型: bool

    • 作用: 标记SSL握手是否完成

    • 特点: 避免重复握手

2. 数据缓冲区

char head_[HEAD_LEN]

  • 类型: 固定大小字符数组

  • 作用: 存储协议头数据

  • 特点:

    • 大小由HEAD_LEN定义(通常8-16字节)

    • 包含魔数、请求类型、body长度等元数据

    • 零拷贝解析提高效率

std::vector<char> body_

  • 类型: 动态字符向量

  • 作用: 存储消息体数据

  • 特点:

    • 初始大小INIT_BUF_SIZE(如1KB)

    • 按需扩容(不超过MAX_BUF_LEN)

    • 复用缓冲区减少内存分配

3. 协议处理变量

rpc_header header_

  • 类型: 协议头结构体

  • 作用: 解析后的协议头信息

  • 典型结构:

    struct rpc_header {
        uint32_t magic;     // 魔数标识
        request_type type;  // 请求类型
        uint32_t body_len;  // 消息体长度
        uint64_t req_id;    // 请求ID
    };

std::uint64_t req_id_

  • 作用: 当前处理的请求ID

  • 特点: 用于请求-响应匹配

request_type req_type_

  • 作用: 标识当前请求类型(req_res/sub_pub)

  • 枚举值:

    enum class request_type {
        req_res = 0,  // 请求-响应模式
        sub_pub = 1   // 发布-订阅模式
    };

4. 写操作相关变量

uint32_t write_size_

  • 作用: 当前正在写入的消息大小

  • 特点: 确保完整写入大数据包

std::deque<message_type> write_queue_

  • message_type定义:

    struct message_type {
        uint64_t req_id;
        request_type req_type;
        std::shared_ptr<std::string> content;
    };
  • 作用: 写消息队列

  • 特点:

    • 保证消息顺序发送

    • 共享指针管理消息内存

    • 实现写操作流水线

5. 连接控制变量

asio::steady_timer timer_

  • 作用: 超时控制定时器

  • 特点:

    • 用于检测空闲连接

    • 可配置超时时间(timeout_seconds_)

    • 自动取消机制

std::size_t timeout_seconds_

  • 作用: 连接超时时间(秒)

  • 特殊值: 0表示不启用超时

bool has_closed_

  • 作用: 连接状态标记

  • 特点: 原子操作保证线程安全

int64_t conn_id_

  • 作用: 连接唯一标识符

  • 用途: 会话管理/日志追踪

6. 回调与路由

router &router_

  • 作用: 请求路由处理器

  • 功能:

    • 维护函数注册表

    • 分发RPC调用

    • 处理序列化/反序列化

回调函数

std::function<void(std::string, std::string, std::weak_ptr<connection>)> callback_;
std::function<void(std::shared_ptr<connection>, std::string)> *on_net_err_ = nullptr;
  • callback_:

    • 类型: 主题+消息+连接弱引用的回调

    • 作用: 处理订阅发布消息

  • on_net_err_:

    • 类型: 网络错误回调指针

    • 作用: 通知外部网络异常

    • 特点: 使用指针避免空回调开销

7. 扩展功能变量

nonstd::any user_data_

  • 作用: 用户自定义数据容器

  • 特点:

    • 类型安全的数据存储

    • 可用于附加会话信息

    • 替代void*的更安全方案

bool delay_

  • 作用: 响应延迟标记

  • 用途:

    • 控制是否立即发送响应

    • 支持异步处理模式

成员函数解析

1. 连接生命周期管理

start() - 启动连接处理

void start() {
    if (is_ssl() && !has_shake_) {
        async_handshake(); // SSL连接需要先握手
    } else {
        read_head(); // 直接开始读取数据
    }
}
  • 功能:启动连接的消息处理循环

  • 逻辑分支

    • SSL连接且未握手 → 执行SSL握手

    • 普通连接或已握手 → 直接读取数据

  • 特点:作为连接处理的统一入口

has_closed() - 连接状态检查

bool has_closed() const { return has_closed_; }
  • 作用:提供线程安全的连接状态查询

  • 使用场景:在需要检查连接是否活跃时调用

2. 响应处理函数

response() - 发送响应

void response(uint64_t req_id, std::string data, request_type req_type = request_type::req_res) {
    assert(data.size() < MAX_BUF_LEN);
    auto sp_data = std::make_shared<std::string>(std::move(data));
    asio::post(socket_.get_executor(), [this, weak = weak_from_this(), sp_data, req_id, req_type] {
        if (auto conn = weak.lock()) {
            response_internal(req_id, std::move(sp_data), req_type);
        }
    });
}
  • 参数

    • req_id:请求ID用于匹配

    • data:响应数据(移动语义)

    • req_type:请求类型(默认请求-响应模式)

  • 关键设计

    • 使用shared_ptr管理数据生命周期

    • 通过weak_ptr安全访问connection对象

    • 在socket的执行器中序列化写操作

pack_and_response() - 打包并响应模板函数

template <typename T>
void pack_and_response(uint64_t req_id, T data) {
    auto result = msgpack_codec::pack_args_str(result_code::OK, std::move(data));
    response(req_id, std::move(result));
}
  • 功能:将数据打包为msgpack格式后发送

  • 特点

    • 自动添加成功结果码(result_code::OK)

    • 支持任意可序列化类型

    • 简化响应发送流程

3. 连接属性管理

连接标识管理

void set_conn_id(int64_t id) { conn_id_ = id; }
int64_t conn_id() const { return conn_id_; }
  • 作用:设置/获取连接唯一标识

  • 用途:用于会话管理和日志追踪

用户数据存储

template <typename T>
void set_user_data(const T &data) { user_data_ = data; }

template <typename T>
T get_user_data() {
    return nonstd::any_cast<T>(user_data_);
}
  • 实现:基于type-erasure的任意数据存储

  • 特点

    • 类型安全的存取接口

    • 可用于附加业务上下文

    • 替代void*的更安全方案

4. 网络信息获取

remote_address() - 获取客户端地址

std::string remote_address() const {
    if (has_closed_) return "";
    asio::error_code ec;
    auto endpoint = socket_.remote_endpoint(ec);
    return ec ? "" : endpoint.address().to_string();
}
  • 功能:获取对端IP地址字符串

  • 错误处理

    • 连接已关闭返回空字符串

    • 获取失败返回空字符串

  • 线程安全:无锁实现,适合并发调用

5. 发布订阅功能

publish() - 发布消息

void publish(const std::string &key, const std::string &data) {
    auto result = msgpack_codec::pack_args_str(result_code::OK, key, data);
    response(0, std::move(result), request_type::sub_pub);
}
  • 特点

    • 使用0作为特殊请求ID

    • 指定sub_pub请求类型

    • 自动打包主题和数据

set_callback() - 设置订阅回调

void set_callback(std::function<void(std::string, std::string, 
                   std::weak_ptr<connection>)> callback) {
    callback_ = std::move(callback);
}
  • 回调参数

    • 主题名称

    • 消息内容

    • 连接弱引用(避免循环引用)

6. SSL/TLS配置

init_ssl_context() - 初始化SSL上下文

void init_ssl_context(const ssl_configure &ssl_conf) {
    asio::ssl::context ssl_context(asio::ssl::context::sslv23);
    ssl_context.set_options(ssl_options);
    ssl_context.use_certificate_chain_file(ssl_conf.cert_file);
    ssl_context.use_private_key_file(ssl_conf.key_file, asio::ssl::context::pem);
    ssl_stream_ = std::make_unique<asio::ssl::stream<asio::ip::tcp::socket&>>(socket_, ssl_context);
}
  • 安全配置

    • 禁用不安全的SSLv2

    • 单次DH密钥交换

    • 加载证书和私钥文件

  • 错误处理:捕获异常并打印日志

7. 其他控制功能

set_delay() - 延迟响应控制

void set_delay(bool delay) { delay_ = delay; }
  • 用途:标记是否需要延迟发送响应

  • 场景:用于异步处理完成后手动发送响应

on_network_error() - 设置网络错误回调

void on_network_error(std::function<void(std::shared_ptr<connection>, 
                        std::string)> &on_net_err) {
    on_net_err_ = &on_net_err;
}
  • 设计特点

    • 使用指针存储回调(避免空回调对象开销)

    • 参数包含连接对象和错误信息

    • 在超时、协议错误等情况下触发

私有成员函数解析

1. 核心消息处理流程

读操作流程

read_head() - 读取消息头
void read_head() {
    reset_timer(); // 重置超时定时器
    async_read_head([this, self](asio::error_code ec, std::size_t length) {
        // 协议头处理逻辑
        rpc_header* header = (rpc_header*)(head_);
        if (header->magic != MAGIC_NUM) {
            close(); // 协议错误立即关闭连接
            return;
        }
        // 解析并验证消息体长度
        if (body_len > 0 && body_len < MAX_BUF_LEN) {
            read_body(header->func_id, body_len); // 继续读取消息体
        }
        else if (body_len == 0) {
            read_head(); // 心跳包,继续读下一个消息头
        }
    });
}
  • 关键点

    • 每次读取前重置超时定时器

    • 严格验证协议魔数和消息长度

    • 支持心跳包(body_len=0)的特殊处理

read_body() - 读取消息体
void read_body(uint32_t func_id, std::size_t size) {
    async_read(size, [this, func_id, self](asio::error_code ec, std::size_t length) {
        cancel_timer(); // 取消当前超时检测
        if (req_type_ == request_type::req_res) {
            // RPC调用路由处理
            auto ret = router_.route(func_id, {body_.data(), length}, ...);
            response_internal(req_id_, std::move(ret.result));
        }
        else if (req_type_ == request_type::sub_pub) {
            // 发布订阅消息回调
            callback_(topic, message, this->shared_from_this());
        }
        read_head(); // 继续读下一个消息
    });
}
  • 关键点

    • 根据请求类型分流处理

    • 自动续读实现持续通信

    • 消息体缓冲区复用

写操作流程

response_internal() - 响应处理
void response_internal(uint64_t req_id, std::shared_ptr<std::string> data) {
    write_queue_.emplace_back(message_type{req_id, req_type, std::move(data)});
    if (write_queue_.size() == 1) {
        write(); // 立即发送如果是队列中唯一消息
    }
}
  • 设计特点

    • 写操作队列化保证顺序

    • 共享指针管理消息内存

    • 触发式发送机制

write() - 实际写入操作
void write() {
    std::array<asio::const_buffer, 2> write_buffers = {
        asio::buffer(&header_, sizeof(rpc_header)),
        asio::buffer(msg.content->data(), write_size_)
    };
    async_write(write_buffers, [this, self](asio::error_code ec, std::size_t length) {
        write_queue_.pop_front();
        if (!write_queue_.empty()) write(); // 继续发送队列中下一条
    });
}
  • 优化点

    • 复合缓冲区减少系统调用

    • 自动连续发送机制

    • 零拷贝数据传递

2. SSL/TLS 安全通信

async_handshake() - SSL握手

void async_handshake() {
    ssl_stream_->async_handshake(asio::ssl::stream_base::server,
        [this, self](const asio::error_code& error) {
            if (!error) {
                has_shake_ = true;
                read_head(); // 握手成功后开始正常通信
            }
        });
}
  • 安全特性

    • 服务端模式握手

    • 状态标记保证只握手一次

    • 错误时立即关闭连接

3. 连接生命周期管理

close() - 连接关闭

void close(bool close_ssl = true) {
#ifdef CINATRA_ENABLE_SSL
    if (close_ssl && ssl_stream_) {
        ssl_stream_->shutdown(ec); // 优雅关闭SSL
    }
#endif
    socket_.shutdown(tcp::socket::shutdown_both);
    socket_.close();
    has_closed_ = true;
}
  • 资源管理

    • 区分SSL和普通关闭

    • 双重关闭保证资源释放

    • 状态标记避免重复关闭

超时控制

reset_timer() - 重置定时器
void reset_timer() {
    timer_.expires_from_now(std::chrono::seconds(timeout_seconds_));
    timer_.async_wait([this, self](const asio::error_code& ec) {
        if (!ec) close(false); // 超时触发连接关闭
    });
}
cancel_timer() - 取消定时器
void cancel_timer() {
    timer_.cancel(); // 正常响应时取消超时检测
}
  • 设计亮点

    • 精确到秒的超时控制

    • 异步等待不阻塞线程

    • 自动续期机制

4. 异步IO模板方法

通用异步IO封装

template <typename Handler>
void async_read_head(Handler handler) {
    if (is_ssl()) {
        asio::async_read(*ssl_stream_, asio::buffer(head_), handler);
    } else {
        asio::async_read(socket_, asio::buffer(head_), handler);
    }
}
  • 模板特性

    • 统一SSL和非SSL接口

    • 完美转发handler

    • 编译期多态

5. 调试支持

日志输出

template <typename... Args> 
void print(Args... args) {
#ifdef _DEBUG
    (std::cout << ... << args) << "\n"; // C++17折叠表达式
#endif
}
  • 调试功能

    • 条件编译的调试输出

    • 支持多参数打印

    • 专用于错误和异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值