0、 前言
TCP、IPC、INPROC 这些不同的底层传输,为什么可以无缝适配所有上层协议(Pair/REQ/PUB/SUB)?
答案就在本文的核心文件:transport.h。
transport.h 是 Nanomsg 整个传输子系统的顶层规范、接口契约、架构基石。它彻底定义了:
-
什么是传输层(Transport)?
-
什么是端点(Endpoint)?
-
什么是管道(Pipe)?
-
传输层必须实现哪些接口、遵循哪些状态机规则?
-
内核如何统一调度 TCP/IPC/INPROC 不同传输?
本文将 逐结构体、逐函数、逐设计思想 解析 transport.h,并结合你已经掌握的 IPC 全套源码 ,做规范与实现的一一映射,彻底打通 Nanomsg 从「内核抽象架构」到「具体 IPC 传输落地」的完整链路。
读完本文,你将彻底理解 Nanomsg 最精髓的设计:协议与传输彻底解耦。
1、Nanomsg 整体四层架构复盘
为了让你快速建立全局视图,先复盘完整四层模型,本文覆盖 第2、3层:
-
应用层 :
nn_socket / nn_bind / nn_connect / nn_send / nn_recv -
协议层(Protocol) :
protocol.h规范,Pair/REQ/PUB/SUB,负责消息路由、收发规则、状态逻辑 -
传输层(Transport) :
transport.h规范,TCP/IPC/INPROC,负责连接管理、字节流收发、异步 IO -
底层工具层:FSM 状态机、usock 异步套接字、msg 消息、list 链表
核心分工:
-
协议层不关心底层是 IPC 还是 TCP,只操作 Pipe 管道;
-
传输层不关心上层是 Pair 还是 REQ,只负责可靠收发字节流、维护连接;
-
transport.h 就是两层之间的严格契约。
二、transport.h 整体模块划分
整个头文件可以精准拆分为 四大核心模块,逻辑层层递进:
-
Opts 配置子系统 :
nn_optset传输层私有配置基类(对应 IPC 自定义缓冲区、Windows 安全属性) -
Endpoint 端点子系统 :
nn_ep绑定/连接地址管理者(每一个 bind/connect 对应一个端点) -
PipeBase 管道基类子系统 :
nn_pipebase所有连接的统一抽象,传输层的核心父类 -
Transport 传输工厂子系统 :
nn_transport协议注册入口(TCP/IPC/INPROC 都是该结构体的实例)
下面我们从「抽象定义」到「IPC 具体实现」逐块深度解析。
3、模块一:nn_optset 传输私有配置规范
3.1 源码定义
c
struct nn_optset_vfptr {
void (*destroy) (struct nn_optset *self);
int (*setopt) (struct nn_optset *self, int option, const void *optval,
size_t optvallen);
int (*getopt) (struct nn_optset *self, void *optval,
size_t *optvallen);
};
struct nn_optset {
const struct nn_optset_vfptr *vfptr;
};
3.2 设计思想
Nanomsg 允许每一种传输协议拥有自己的私有配置项:
-
TCP:保活时间、Nagle、端口复用、TTL
-
IPC:Windows 安全属性、IPC 专属收发缓冲区大小
-
INPROC:无本地传输配置
nn_optset 是所有这些「传输私有配置」的统一基类,基于 C 语言多态实现。
3.3 IPC 传输精准对应
你之前看过的 IPC 配置代码,就是该规范的具体实现:
-
nn_ipc_optset继承自nn_optset -
实现了
destroy/setopt/getopt三个虚函数 -
扩展了
sec_attr/outbuffersz/inbuffersz私有字段
这就是为什么 IPC 可以拥有专属 Socket 选项,且完全兼容内核框架。
4、模块二:nn_ep 端点系统(Endpoint)
4.1 核心概念:什么是 Endpoint?
官方最精准定义:
每一次 nn_bind() 或 nn_connect(),都会创建一个 Endpoint(端点)。
一个 Endpoint 对应唯一的地址字符串 (如 ipc:///tmp/test.sock、tcp://127.0.0.1:8888)。
端点是传输层的顶层管理者:
-
服务端:一个 Endpoint 监听一个地址,可以接受无数个连接(生成无数 Pipe)
-
客户端:一个 Endpoint 对应一个连接,生成一个 Pipe
4.2 端点操作集 nn_ep_ops
c
struct nn_ep_ops {
void (*stop) (void *);
void (*destroy) (void *);
};
所有传输的端点(bipc/cipc)必须实现两个生命周期函数:
-
stop:优雅停止端点,允许发送残留数据
-
destroy:彻底销毁内存资源
4.3 端点核心 API(全局统一接口)
这组 API 是内核给传输层的标准能力,所有 IPC/TCP 代码都在调用:
| 函数 | 作用 | IPC 调用场景 |
|---|---|---|
| nn_ep_tran_setup | 绑定端点与传输层实现、回调函数 | bipc/cipc 初始化时绑定 ep_ops |
| nn_ep_stopped | 通知内核端点已完全停止 | shutdown 收尾阶段调用 |
| nn_ep_getctx | 获取 AIO 异步上下文 | 初始化 FSM、定时器、usock |
| nn_ep_getaddr | 获取绑定/连接的地址字符串 | cipc 组装 sockaddr_un 路径 |
| nn_ep_getopt | 读取 socket 配置(缓冲区、重连间隔) | 读取 RECONNECT_IVL、SNDBUF、RCVBUF |
| nn_ep_ispeer | 校验对端协议是否兼容 | 保证 Pair 只连 Pair、REQ 只连 REP |
| nn_ep_set_error/clear_error | 设置/清除端点错误状态 | 连接失败记录 errno、重连成功清空错误 |
| nn_ep_stat_increment | 统计连接数、错误数、断连数 | cipc/bipc 全程统计打点 |
4.4 IPC 端点落地对照
你之前看的 IPC 顶层代码:
-
nn_bipc_create:服务端端点实现 -
nn_cipc_create:客户端端点实现 -
两者都通过
nn_ep_tran_setup注册stop/destroy回调 -
所有错误、统计、配置读取,全部调用上述标准 API
这就是为什么 IPC 代码规范、统一、可替换、可扩展。
5、模块三:nn_pipebase 管道基类(传输层核心)
Pipe 是 Nanomsg 最重要的概念,没有之一。
5.1 核心定义
Endpoint = 地址管理 ,Pipe = 真实连接
每一条真实的 TCP/IPC 连接,都会被抽象为一个 Pipe 管道。
-
服务端 listen 一个端点 → accept 多次 → 生成多个 Pipe
-
客户端 connect 一个端点 → 成功后生成一个 Pipe
5.2 管道状态标记
c
#define NN_PIPEBASE_RELEASE 1
#define NN_PIPEBASE_PARSED 2
-
NN_PIPEBASE_RELEASE:管道暂停收发,需要上层事件唤醒(异步流控核心)
-
NN_PIPEBASE_PARSED:仅 INPROC 内部传输使用,消息已解析,无需重组
5.3 管道虚函数表(传输层必须实现)
c
struct nn_pipebase_vfptr {
int (*send) (struct nn_pipebase *self, struct nn_msg *msg);
int (*recv) (struct nn_pipebase *self, struct nn_msg *msg);
};
所有传输的连接实体,必须实现 send/recv:
-
IPC 连接(sipc 会话)实现异步收发
-
TCP 连接同理
-
协议层统一调用管道收发,不感知底层差异
5.4 nn_pipebase 核心结构体(传输层父类)
这是所有连接对象的公共头部:
c
struct nn_pipebase {
struct nn_fsm fsm;
const struct nn_pipebase_vfptr *vfptr;
uint8_t state;
uint8_t instate;
uint8_t outstate;
struct nn_sock *sock;
void *data;
struct nn_fsm_event in;
struct nn_fsm_event out;
struct nn_ep_options options;
};
关键字段详解:
-
fsm:每个连接自带状态机,异步事件驱动
-
in/out 事件:可读/可写事件,用于唤醒协议层回调
-
sock:关联上层协议 Socket(Pair/REQ 等)
-
options:收发优先级、IPv4 仅栈等通用配置
5.5 管道生命周期核心 API(闭环关键)
这组 API 是 传输层与协议层的桥梁,是整个 Nanomsg 调度的心脏:
-
nn_pipebase_start:连接建立成功 → 创建上层 Pipe → 触发协议层 add 回调 -
nn_pipebase_stop:连接断开 → 触发协议层 rm 回调 -
nn_pipebase_received:收完一条完整消息 → 触发协议层 in 可读回调 -
nn_pipebase_sent:发完一条消息 → 触发协议层 out可写回调
5.6 IPC 完整链路映射
IPC 传输全过程完全贴合该规范:
-
cipc/aipc 建立连接
-
sipc 会话就绪,调用
nn_pipebase_start -
内核通知 Pair 协议
add新管道 -
收到消息后调用
nn_pipebase_received→ 触发 Pairin回调 -
发送完成调用
nn_pipebase_sent→ 触发 Pairout回调 -
断连调用
nn_pipebase_stop→ 触发 Pairrm回调
这就是为什么协议层完全不用管 TCP/IPC,只需要管管道事件。
6、模块四:nn_transport 传输工厂(顶层注册入口)
nn_transport 是所有传输协议的身份证与入口。
6.1 结构体定义
c
struct nn_transport {
const char *name;
int id;
void (*init) (void);
void (*term) (void);
int (*bind) (struct nn_ep *);
int (*connect) (struct nn_ep *);
struct nn_optset *(*optset) (void);
};
6.2 字段逐行解析
-
name:协议名(ipc / tcp / inproc),匹配 URL 前缀
-
id:传输唯一 ID
-
init/term:传输全局初始化、销毁
-
bind :服务端创建端点(IPC 对应
nn_bipc_create) -
connect :客户端创建端点(IPC 对应
nn_cipc_create) -
optset:创建传输私有配置对象
6.3 IPC 传输最终落地(完美对照)
你之前看过的 IPC 顶层注册代码,就是该结构体的实例:
c
struct nn_transport nn_ipc = {
"ipc",
NN_IPC,
NULL,
NULL,
nn_ipc_bind,
nn_ipc_connect,
nn_ipc_optset
};
对应关系:
-
nn_ipc_bind→ 调用nn_bipc_create服务端 -
nn_ipc_connect→ 调用nn_cipc_create客户端 -
nn_ipc_optset→ 创建 IPC 专属配置
至此,IPC 传输从内核规范到落地实现 100% 闭环。
7、终极串联:transport.h + IPC 完整运行链路
7.1 应用层调用流程
Plain
nn_socket() → nn_bind("ipc://xxx")
7.2 内核路由流程
-
内核解析 URL 协议名
ipc,匹配nn_transport实例 -
调用 transport 的
bind方法 →nn_ipc_bind -
创建 IPC 服务端端点
bipc,初始化 ep 端点 -
启动监听 socket,等待客户端连接
-
客户端 connect 成功 → 生成 sipc 会话 + pipebase 管道
-
调用
nn_pipebase_start上报协议层 -
Pair 协议触发 add/in/out 回调,开始消息收发
8、核心设计思想总结(全文精髓)
8.1 三层彻底解耦(Nanomsg 灵魂)
-
协议层:只管消息规则(一对一、发布订阅、问答),不管连接
-
传输层:只管连接、IO、重连、字节流,不管消息规则
-
内核抽象层:transport.h 统一契约,让两层永远不耦合
8.2 为什么 IPC/TCP 代码高度相似?
因为遵守同一套 transport.h 规范:
-
状态机模型一致
-
端点生命周期一致
-
管道事件回调一致
-
配置管理机制一致
唯一区别:底层 socket 类型、地址结构、平台适配细节。
8.3 核心抽象层级一句话总结
-
optset:传输私有配置抽象
-
ep:地址与监听/连接管理抽象
-
pipebase:真实连接与 IO 读写抽象
-
transport:协议工厂与全局入口抽象
9、结合全套源码的知识闭环
至此,你已经完整掌握 Nanomsg IPC 全栈源码:
-
transport.h:传输层顶层架构规范
-
ipc 传输入口:nn_ipc 注册、optset 配置
-
服务端:bipc(监听管理)+ aipc(异步 accept)
-
客户端:cipc(异步 connect + 退避重连)
-
会话层:sipc 消息帧收发、streamhdr 握手
-
协议层:Pair 一对一双向通信模型
-
内核规范:protocol.h 套接字、管道、多态模型