文章目录
-
-
- [一、Session 的本质](#一、Session 的本质)
- [二、Session 的核心结构](#二、Session 的核心结构)
- [三、Session 的生命周期](#三、Session 的生命周期)
-
- [**1. 创建阶段**](#1. 创建阶段)
- [**2. 启动阶段**](#2. 启动阶段)
- [**3. 连接建立阶段**](#3. 连接建立阶段)
- [**4. 消息转发阶段**](#4. 消息转发阶段)
- [**5. 错误处理与重连**](#5. 错误处理与重连)
- [**6. 终止阶段**](#6. 终止阶段)
- [四、Session 与 Socket 的对比](#四、Session 与 Socket 的对比)
- [五、Session 的状态机](#五、Session 的状态机)
- [六、特殊 Session 类型](#六、特殊 Session 类型)
-
- [**1. req_session_t**](#1. req_session_t)
- [**2. hello_msg_session_t**](#2. hello_msg_session_t)
- [七、ZAP 认证机制](#七、ZAP 认证机制)
- 八、总结
-
一、Session 的本质
Session 是 ZeroMQ 中管理单个网络连接的生命周期对象,位于 I/O 线程中,负责:
- 网络连接的建立和维护
- 协议握手和认证
- 自动重连
- 与 socket 之间的消息中转
二、Session 的核心结构
cpp
class session_base_t : public own_t, // 对象生命周期管理
public io_object_t, // I/O 事件处理
public i_pipe_events // 管道事件监听
{
// === 核心成员变量 ===
const bool _active; // 是否主动连接(connect 创建 vs bind 创建)
pipe_t *_pipe; // 与 socket 通信的管道
pipe_t *_zap_pipe; // ZAP 认证管道(可选)
i_engine *_engine; // 协议引擎(TCP/IPC/WS 等)
socket_base_t *_socket; // 所属的 socket
io_thread_t *_io_thread; // 所属的 I/O 线程
address_t *_addr; // 连接地址信息
bool _pending; // 是否等待消息发送完成
bool _incomplete_in; // 是否有未完成的多部分消息
bool _has_linger_timer; // linger 定时器是否运行
};
三、Session 的生命周期
1. 创建阶段
cpp
// socket_base.cpp: connect_internal (TCP 模式)
// 第 1104 行
session_base_t *session = session_base_t::create (
io_thread, // I/O 线程
true, // active=true 表示主动连接
this, // socket 指针
options, // 配置选项
paddr // 地址信息
);
// session_base.cpp: create() 第 28-87 行
session_base_t *s = NULL;
switch (options_.type) {
case ZMQ_REQ:
s = new req_session_t (...); // 特殊 socket 类型有特殊 session
break;
// ... 其他类型
default:
s = new session_base_t (...); // 普通 session
}
2. 启动阶段
cpp
// 第 1 步:socket 发送 plug 命令给 session
send_plug (session); // 通过命令队列
// 第 2 步:session 收到 plug 命令
// session_base.cpp: process_plug() 第 822-826 行
void zmq::session_base_t::process_plug ()
{
if (_active)
start_connecting (false); // 开始连接
}
// 第 3 步:创建 connecter
// session_base.cpp: start_connecting() 第 585-760 行
void zmq::session_base_t::start_connecting (bool wait_)
{
io_thread_t *io_thread = choose_io_thread (options.affinity);
// 根据协议类型创建不同的 connecter
if (_addr->protocol == protocol_name::tcp) {
connecter = new tcp_connecter_t (io_thread, this, options, _addr, wait_);
}
// ... IPC, WS, TIPC 等
launch_child (connecter); // 启动 connecter
}
3. 连接建立阶段
TCP 连接建立流程:
Connecter Session Engine
| | |
|-- TCP connect() --------------->| |
| | |
|-- 创建 engine ----------------->| |
| | |
| |-- process_attach(engine) ->|
| | |
| | |-- engine->plug()
| | | 注册到轮询器
| | |
| |-- engine_ready() --------->|
| | |
| |-- 创建 pipe -------------->|
| | |
| |-- send_bind(socket) ------->|
| | |
v v v
关键代码:
cpp
// session_base.cpp: process_attach() 第 382-393 行
void zmq::session_base_t::process_attach (i_engine *engine_)
{
zmq_assert (engine_ != NULL);
zmq_assert (!_engine);
_engine = engine_;
if (!engine_->has_handshake_stage ())
engine_ready (); // 无需握手,直接就绪
// 将 engine 插入到 I/O 线程的轮询器
_engine->plug (_io_thread, this);
}
// session_base.cpp: engine_ready() 第 395-425 行
void zmq::session_base_t::engine_ready ()
{
// 创建与 socket 通信的管道
if (!_pipe && !is_terminating ()) {
object_t *parents[2] = {this, _socket};
pipe_t *pipes[2] = {NULL, NULL};
int hwms[2] = {options.rcvhwm, options.sndhwm};
bool conflates[2] = {conflate, conflate};
const int rc = pipepair (parents, pipes, hwms, conflates);
// 设置事件接收器
pipes[0]->set_event_sink (this);
_pipe = pipes[0];
// 设置端点对
pipes[0]->set_endpoint_pair (_engine->get_endpoint ());
pipes[1]->set_endpoint_pair (_engine->get_endpoint ());
// 让 socket 附加到管道的远端
send_bind (_socket, pipes[1]);
}
}
4. 消息转发阶段
从 Socket 到网络(发送):
cpp
// 1. Socket 写入消息到 pipe
socket->send(msg)
↓
pipe_t::write(msg) // 写入无锁队列
↓
pipe_t::flush()
↓
send_activate_read(peer) // 发送命令到 session
// 2. Session 收到 activate_read 命令
// session_base.cpp: read_activated() 第 276-296 行
void zmq::session_base_t::read_activated (pipe_t *pipe_)
{
if (likely (pipe_ == _pipe))
_engine->restart_output (); // 通知 engine 可以发送
}
// 3. Engine 从 pipe 读取并发送到网络
// stream_engine_base.cpp: restart_output()
engine->restart_output()
↓
in_event() / out_event() // 轮询器触发
↓
_decoder->decode() // 解码消息
↓
socket->send() // 实际网络发送
从网络到 Socket(接收):
cpp
// 1. 网络数据到达,轮询器触发
engine->in_event()
↓
_decoder->decode() // 解码数据
↓
session->push_msg(msg) // 推送到 pipe
// 2. Session 推送到 pipe
// session_base.cpp: push_msg() 第 157-171 行
int zmq::session_base_t::push_msg (msg_t *msg_)
{
if (_pipe && _pipe->write (msg_)) {
msg_->init (); // 重置消息
return 0;
}
errno = EAGAIN;
return -1;
}
// 3. Pipe 通知 socket
pipe_t::write_activated()
↓
socket->read_activated()
↓
socket->recv() // 用户接收
5. 错误处理与重连
cpp
// session_base.cpp: engine_error() 第 427-482 行
void zmq::session_base_t::engine_error (bool handshaked_,
error_reason_t reason_)
{
_engine = NULL; // 清除 engine
// 清理管道
if (_pipe) {
clean_pipes ();
// 发送断开消息(如果配置)
if (options.can_recv_disconnect_msg)
_pipe->send_disconnect_msg ();
}
switch (reason_) {
case connection_error:
case timeout_error:
if (_active) {
reconnect (); // 主动连接才重连
break;
}
// FALLTHROUGH
case protocol_error:
if (_pending)
_pipe->terminate (false);
else
terminate (); // 终止 session
break;
}
}
// session_base.cpp: reconnect() 第 542-583 行
void zmq::session_base_t::reconnect ()
{
// 处理 hiccup(颠簸)
if (_pipe && options.immediate == 1) {
_pipe->hiccup (); // 通知 socket 连接中断
_pipe->terminate (false);
_pipe = NULL;
}
// 重新启动连接
if (options.reconnect_ivl > 0)
start_connecting (true); // 重新开始连接流程
else
send_term_endpoint (_socket, ep); // 通知 socket 端点终止
}
6. 终止阶段
cpp
// session_base.cpp: process_term() 第 484-521 行
void zmq::session_base_t::process_term (int linger_)
{
// 如果没有管道,立即终止
if (!_pipe && !_zap_pipe) {
own_t::process_term (0);
return;
}
_pending = true;
if (_pipe != NULL) {
// 设置 linger 定时器
if (linger_ > 0) {
add_timer (linger_, linger_timer_id);
_has_linger_timer = true;
}
// 终止管道(等待消息发送完成)
_pipe->terminate (linger_ != 0);
}
if (_zap_pipe != NULL)
_zap_pipe->terminate (false);
}
// session_base.cpp: timer_event() 第 523-533 行
void zmq::session_base_t::timer_event (int id_)
{
zmq_assert (id_ == linger_timer_id);
_has_linger_timer = false;
// Linger 超时,强制终止
zmq_assert (_pipe);
_pipe->terminate (false);
}
// session_base.cpp: pipe_terminated() 第 240-274 行
void zmq::session_base_t::pipe_terminated (pipe_t *pipe_)
{
if (pipe_ == _pipe) {
_pipe = NULL;
// 取消定时器
if (_has_linger_timer) {
cancel_timer (linger_timer_id);
_has_linger_timer = false;
}
}
// 如果所有管道都终止了,继续销毁流程
if (_pending && !_pipe && !_zap_pipe) {
_pending = false;
own_t::process_term (0);
}
}
四、Session 与 Socket 的对比
| 特性 | Socket | Session |
|---|---|---|
| 数量 | 1 个(用户创建) | N 个(每个连接 1 个) |
| 所属线程 | 应用线程 | I/O 线程 |
| 可见性 | 用户可见 | 用户不可见 |
| 职责 | 消息路由、多连接管理 | 单个连接管理 |
| 重连 | ❌ 不处理 | ✅ 自动重连 |
| 协议处理 | ❌ 不处理 | ✅ 通过 engine |
| ZAP 认证 | ❌ 不处理 | ✅ 处理 |
| 生命周期 | 用户控制 | 系统自动控制 |
五、Session 的状态机
┌─────────────────────────────────────────────────────────────────┐
│ Session 状态机 │
└─────────────────────────────────────────────────────────────────┘
创建
↓
┌──────────────────┐
│ 初始状态 │
│ - _engine = NULL │
│ - _pipe = NULL │
└────────┬─────────┘
│
│ process_plug()
↓
┌──────────────────┐
│ 连接中 │
│ - 创建 connecter │
│ - TCP connect() │
└────────┬─────────┘
│
│ 连接成功
↓
┌──────────────────┐
│ 握手阶段 │
│ - 创建 engine │
│ - 协议握手 │
│ - ZAP 认证 │
└────────┬─────────┘
│
│ 握手成功
↓
┌──────────────────┐
│ 就绪状态 │
│ - engine_ready()│
│ - 创建 pipe │
│ - 消息转发 │
└────────┬─────────┘
│
│ 错误/断开
↓
┌──────────────────┐
│ 错误处理 │
│ - engine_error()│
│ - 清理管道 │
└────────┬─────────┘
│
│ 需要重连?
├───────────────┐
│ 是 │ 否
↓ ↓
┌──────────────────┐ ┌──────────────┐
│ 重连 │ │ 终止 │
│ - reconnect() │ │ - terminate()│
│ - start_connecting() │ │ - 销毁 │
└──────────────────┘ └──────────────┘
六、特殊 Session 类型
1. req_session_t
用于 REQ socket,处理严格的请求 - 响应模式:
cpp
class req_session_t : public session_base_t {
enum {
bottom, // 底部(可以发送请求)
body, // 消息体中
request_id // 请求 ID
} _state;
// 确保严格的请求 - 响应顺序
int push_msg (msg_t *msg_);
};
2. hello_msg_session_t
支持发送 Hello 消息的 session:
cpp
class hello_msg_session_t : public session_base_t {
bool _new_pipe;
// 连接建立后自动发送 hello 消息
int pull_msg (msg_t *msg_) {
if (_new_pipe) {
msg_->init_buffer (options.hello_msg);
_new_pipe = false;
return 0;
}
return session_base_t::pull_msg (msg_);
}
};
七、ZAP 认证机制
cpp
// session_base.cpp: zap_connect() 第 334-375 行
int zmq::session_base_t::zap_connect ()
{
// 查找 ZAP socket
endpoint_t peer = find_endpoint ("inproc://zeromq.zap.01");
// 创建与 ZAP socket 的管道
object_t *parents[2] = {this, peer.socket};
pipepair (parents, new_pipes, ...);
_zap_pipe = new_pipes[0];
_zap_pipe->set_event_sink (this);
send_bind (peer.socket, new_pipes[1]);
}
// 认证流程:
// 1. Engine 收到连接请求
// 2. Session 发送认证请求到 ZAP socket
// 3. ZAP socket 返回认证结果
// 4. Session 通知 engine 认证结果
八、总结
Session 是 ZeroMQ 架构中的关键组件:
- 承上启下:连接 Socket(应用层)和 Engine(协议层)
- 隔离保护:将复杂的网络操作隔离在 I/O 线程
- 自动恢复:处理重连、错误恢复等复杂逻辑
- 协议抽象:通过 engine 接口支持多种协议
- 认证支持:集成 ZAP 认证机制
- 生命周期管理:自动管理连接的创建和销毁
设计哲学:
- 单一职责:一个 session 管理一个连接
- 异步非阻塞:所有操作在 I/O 线程异步完成
- 命令模式:通过命令队列实现跨线程通信
- 状态机:清晰的状态转换逻辑
- 可扩展性:通过继承支持特殊 socket 类型
这种设计使得 ZeroMQ 能够高效、可靠地管理大量并发连接,同时保持简洁的用户 API。