Nanomsg 源码深剖:transport.h 传输层架构规范 + IPC 传输完整落地实现

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层

  1. 应用层nn_socket / nn_bind / nn_connect / nn_send / nn_recv

  2. 协议层(Protocol)protocol.h 规范,Pair/REQ/PUB/SUB,负责消息路由、收发规则、状态逻辑

  3. 传输层(Transport)transport.h 规范,TCP/IPC/INPROC,负责连接管理、字节流收发、异步 IO

  4. 底层工具层:FSM 状态机、usock 异步套接字、msg 消息、list 链表

核心分工

  • 协议层不关心底层是 IPC 还是 TCP,只操作 Pipe 管道;

  • 传输层不关心上层是 Pair 还是 REQ,只负责可靠收发字节流、维护连接;

  • transport.h 就是两层之间的严格契约


二、transport.h 整体模块划分

整个头文件可以精准拆分为 四大核心模块,逻辑层层递进:

  1. Opts 配置子系统nn_optset 传输层私有配置基类(对应 IPC 自定义缓冲区、Windows 安全属性)

  2. Endpoint 端点子系统nn_ep 绑定/连接地址管理者(每一个 bind/connect 对应一个端点)

  3. PipeBase 管道基类子系统nn_pipebase 所有连接的统一抽象,传输层的核心父类

  4. 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.socktcp://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 传输全过程完全贴合该规范:

  1. cipc/aipc 建立连接

  2. sipc 会话就绪,调用 nn_pipebase_start

  3. 内核通知 Pair 协议 add 新管道

  4. 收到消息后调用 nn_pipebase_received → 触发 Pair in 回调

  5. 发送完成调用 nn_pipebase_sent → 触发 Pair out 回调

  6. 断连调用 nn_pipebase_stop → 触发 Pair rm 回调

这就是为什么协议层完全不用管 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 内核路由流程

  1. 内核解析 URL 协议名 ipc,匹配 nn_transport 实例

  2. 调用 transport 的 bind 方法 → nn_ipc_bind

  3. 创建 IPC 服务端端点 bipc,初始化 ep 端点

  4. 启动监听 socket,等待客户端连接

  5. 客户端 connect 成功 → 生成 sipc 会话 + pipebase 管道

  6. 调用nn_pipebase_start 上报协议层

  7. 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 全栈源码:

  1. transport.h:传输层顶层架构规范

  2. ipc 传输入口:nn_ipc 注册、optset 配置

  3. 服务端:bipc(监听管理)+ aipc(异步 accept)

  4. 客户端:cipc(异步 connect + 退避重连)

  5. 会话层:sipc 消息帧收发、streamhdr 握手

  6. 协议层:Pair 一对一双向通信模型

  7. 内核规范:protocol.h 套接字、管道、多态模型

相关推荐
哎呦,帅小伙哦6 小时前
Nanomsg 源码深度剖析:从 protocol.h 内核抽象到 Pair 一对一通信全实现
linux·nanomsg
哎呦,帅小伙哦6 天前
Nanomsg usock 模块:Socket 选项与错误码介绍
linux·中间件·nanomsg
哎呦,帅小伙哦7 天前
Nanomsg中的usock:一个高效的异步 Socket 封装
nanomsg
哎呦,帅小伙哦15 天前
Nanomsg中间件utils中部分工具学习记录
学习·中间件·nanomsg
哎呦,帅小伙哦7 个月前
Nanomsg库CMakeLists.txt文件阅读笔记
cmakelist.txt·nanomsg