C 与 C++ 实现
1. C 实现的定位
Aeron 的 C 代码不是 Java 的 JNI 封装,而是独立、完整的实现,与 Java 版本共享相同的协议和数据结构定义。两者可以互操作——Java Driver 可以服务 C Client,反之亦然。
┌──────────────────┐ ┌─────────────────────┐
│ 应用 (C) │ │ 应用 (Java) │
├──────────────────┤ ├─────────────────────┤
│ aeron_client │ │ aeron-client │
│ (C) │ │ (Java) │
├──────────────────┤ ├─────────────────────┤
│ │ │ │ │ │
│ ┌─────▼──────────────────────────▼─────┐ │
│ │ 共享内存 (CNC + Log Buffers) │ │
│ ├──────────────────────────────────────┤ │
│ │ aeron_driver (C) or MediaDriver (Java) │
│ └──────────────────────────────────────┘ │
└───────────────────────────────────────────────────┘
C 实现的典型使用场景:
- 低延迟交易系统:避免 Java GC 停顿
- 嵌入式设备:资源受限环境
- FFI 集成:C ABI 可从 Rust、Go、Python 等直接调用
2. C 模块结构
C 代码分布在各模块的 src/main/c/ 路径下,~150 个 .c 文件 + ~150 个 .h 文件:
aeron-client/src/main/c/
├── aeronc.h # C 客户端主头文件(公开 API)
├── aeron_client.c # Client 实现
├── aeron_publication.c # Publication
├── aeron_subscription.c # Subscription
├── aeron_client_conductor.c # 客户端协调器
├── concurrent/ # Lock-Free 数据结构
│ ├── aeron_mpsc_rb.c # Multi-Producer Single-Consumer Ring Buffer
│ ├── aeron_spsc_rb.c # Single-Producer Single-Consumer Ring Buffer
│ ├── aeron_broadcast_receiver.c
│ ├── aeron_broadcast_transmitter.c
│ ├── aeron_atomic.c # 原子操作封装(CAS, Fence)
│ └── aeron_logbuffer_descriptor.c
├── collections/ # 自定义集合类型
│ ├── aeron_int64_to_ptr_hash_map.c
│ ├── aeron_str_to_ptr_hash_map.c
│ └── aeron_bit_set.c
├── protocol/ # 协议 flyweight(C 版本)
│ └── aeron_udp_protocol.c
├── util/ # 工具函数
│ ├── aeron_error.c
│ ├── aeron_clock.c
│ ├── aeron_parse_util.c
│ └── aeron_netutil.c
└── uri/ # URI 解析
└── aeron_uri.c
aeron-driver/src/main/c/
├── aeronmd.h # C 驱动主头文件(公开 API)
├── aeron_driver.c # Driver 入口
├── aeron_driver_conductor.c # 驱动协调器
├── aeron_driver_sender.c # 发送器
├── aeron_driver_receiver.c # 接收器
├── aeron_flow_control.c # 流控
├── aeron_congestion_control.c # 拥塞控制
├── aeron_publication_image.c # 镜像接收
├── aeron_ipc_publication.c # IPC 发布
├── aeron_network_publication.c # 网络发布
├── aeron_loss_detector.c # 丢包检测
├── aeron_retransmit_handler.c # 重传处理
├── agent/ # Agent 线程模型
│ └── aeron_driver_agent.c
├── media/ # UDP 传输层
│ ├── aeron_udp_channel.c
│ ├── aeron_send_channel_endpoint.c
│ ├── aeron_receive_channel_endpoint.c
│ └── aeron_udp_channel_transport.c
├── concurrent/ # 驱动特有的 lock-free 结构
│ └── aeron_logbuffer_unblocker.c
└── uri/ # URI 解析(驱动侧)
└── aeron_driver_uri.c
3. C Client API:与 Java 的对应关系
3.1 公开 API
aeronc.h 是 C 客户端的公共头文件:
// 创建和配置
aeron_context_t *aeron_context_init(aeron_context_t *context);
aeron_t *aeron_init(aeron_t *client, aeron_context_t *context);
aeron_t *aeron_connect(aeron_t *client);
// Publication
aeron_publication_t *aeron_add_publication(
aeron_t *client, const char *channel, int32_t stream_id);
int64_t aeron_publication_offer(
aeron_publication_t *publication,
const uint8_t *buffer, size_t length,
aeron_reserved_value_supplier_t reserved_value_supplier, void *clientd);
// Subscription
aeron_subscription_t *aeron_add_subscription(
aeron_t *client, const char *channel, int32_t stream_id,
aeron_on_available_image_t on_available_image,
void *on_available_image_clientd,
aeron_on_unavailable_image_t on_unavailable_image,
void *on_unavailable_image_clientd);
int aeron_subscription_poll(
aeron_subscription_t *subscription,
aeron_fragment_handler_t handler, void *clientd, size_t fragment_limit);
// 事件循环驱动
int aeron_client_conductor_do_work(aeron_client_conductor_t *conductor);
3.2 Java ↔ C 对应表
| 概念 | Java | C |
|---|---|---|
| Client 入口 | Aeron.connect(ctx) | aeron_connect(client) |
| 配置 | Aeron.Context | aeron_context_t |
| 发布 | Publication.offer() | aeron_publication_offer() |
| 订阅 | Subscription.poll() | aeron_subscription_poll() |
| 协调器 | ClientConductor.doWork() | aeron_client_conductor_do_work() |
| Atomic CAS | Unsafe.compareAndSwapLong() | aeron_cmpxchg64() |
| Volatile Read | Unsafe.getLongVolatile() | aeron_get_volatile64() |
| RingBuffer (MPSC) | ManyToOneRingBuffer | aeron_mpsc_rb_t |
3.3 原子操作封装
concurrent/aeron_atomic.c 封装跨平台的原子操作:
// CAS
int64_t aeron_cmpxchg64(volatile int64_t *ptr, int64_t expected, int64_t desired);
// 内存屏障
void aeron_lock_signal_fence(); // store fence (sfence / dmb)
void aeron_lock_load_fence(); // load fence (lfence / dmb)
void aeron_lock_full_fence(); // full fence (mfence / dmb)
// Volatile 读写
int64_t aeron_get_volatile64(volatile int64_t *src);
void aeron_put_volatile64(volatile int64_t *dst, int64_t value);
底层实现在不同平台:
- Linux x86:使用
__sync_bool_compare_and_swap/__sync_synchronize - ARM:使用
__atomic_compare_exchange_n/__atomic_thread_fence - MSVC:使用
InterlockedCompareExchange64/_ReadWriteBarrier
4. C 驱动实现
4.1 入口与线程模型
aeronmd.h 是 C 驱动的公共头文件。C 驱动支持四种线程模式 aeronmd.h:56-63:
| 模式 | 说明 |
|---|---|
AERON_THREADING_MODE_DEDICATED | 三独立线程(Conductor/Sender/Receiver),与 Java 默认相同 |
AERON_THREADING_MODE_SHARED_NETWORK | Sender + Receiver 共享同一线程 |
AERON_THREADING_MODE_SHARED | Conductor + Sender + Receiver 全部共享线程 |
AERON_THREADING_MODE_INVOKER | 手动驱动(不创建线程) |
4.2 驱动启动
aeron_driver_context_init(&context); // 创建配置上下文
aeron_driver_context_set_dir(&context, "/dev/shm/aeron"); // 设置目录
aeron_driver_init(&driver, &context); // 初始化驱动
aeron_driver_start(driver, false, false); // 启动线程/手动驱动
// ... 运行时 ...
aeron_driver_close(driver); // 停止并清理
4.3 驱动协调器
aeron_driver_conductor.c 是 C 驱动中最复杂的文件,与 Java DriverConductor 对应:
aeron_driver_conductor_do_work(conductor)
├── aeron_mpsc_rb_read(to_driver_commands) // 读取客户端命令
├── 命令处理
│ ├── AERON_COMMAND_ADD_PUBLICATION
│ │ ├── aeron_ipc_publication_create() 或
│ │ └── aeron_network_publication_create()
│ ├── AERON_COMMAND_REMOVE_PUBLICATION
│ ├── AERON_COMMAND_ADD_SUBSCRIPTION
│ └── AERON_COMMAND_REMOVE_SUBSCRIPTION
├── 周期性任务(定时器到期时)
│ ├── 客户端心跳超时检查
│ ├── Publication 空闲超时
│ └── 命名解析更新
└── 资源清理
4.4 C 驱动 Sender
aeron_driver_sender_do_work(sender)
├── 处理命令队列 (来自 conductor)
├── 轮询所有 aeron_network_publication_t
│ └── aeron_network_publication_send()
│ ├── 检查 term buffer tail counter
│ ├── 组装协议头 (DataHeader)
│ ├── sendmsg() 系统调用
│ └── 更新 sender position
├── 检查 aeron_retransmit_handler_t (NAK 重传)
└── 流控检查
4.5 C 驱动 Receiver
aeron_driver_receiver_do_work(receiver)
├── 处理命令队列
├── epoll / kqueue / select (跨平台 I/O 多路复用)
│ └── 对每个就绪的 receive_channel_endpoint:
│ └── recvmsg() → on_data_packet()
│ ├── 解析 DataHeader
│ ├── 查找/创建 aeron_publication_image_t
│ ├── 写入 image 的 term buffer
│ └── LossDetector 扫描
├── 轮询所有 publication_image
│ └── aeron_publication_image_send_status_message()
│ ├── 组装 Status Message 帧
│ └── sendmsg() 发送
└── 清理 PendingSetup
5. C++ 示例
C++ 示例位于 aeron-samples/src/main/cpp/,使用 C API 的简单 C++ 包装:
- BasicPublisher.cpp — 基础发布者
- BasicSubscriber.cpp — 基础订阅者
- PingPong.cpp — 延迟基准测试
- Throughput.cpp — 吞吐量基准测试
- StreamingPublisher.cpp — 流式发布
C++ 示例通过 extern "C" 包含 C 头文件,无额外的 C++ 中间层封装。
6. 构建系统
C/C++ 代码使用 CMake 构建,顶层 CMakeLists.txt 管理:
cmake 选项:
BUILD_AERON_DRIVER=ON ← 构建 C 驱动
BUILD_AERON_ARCHIVE_API=ON ← 构建 Archive C 客户端
AERON_TESTS=ON ← 构建测试(使用 Google Test)
AERON_BUILD_SAMPLES=ON ← 构建示例
构建依赖:
- Google Test 1.14.0(自动下载)
- HdrHistogram_c 0.11.9(自动下载)
- C11 编译器(GCC/Clang/MSVC)+ CMake 3.13+
7. 关键设计决策
| 决策 | 实现 |
|---|---|
| C 独立实现 | 不依赖 JNI,共享协议和内存布局定义 |
| 跨平台原子操作 | aeron_cmpxchg64() 封装 x86/ARM/MSVC 差异 |
| POSIX I/O | sendmsg/recvmsg + epoll/kqueue/select |
| 手动内存管理 | C 风格 _init/_close 生命周期,无 GC |
| 四种线程模式 | 从 Dedicated 到 Invoker,灵活适配场景 |
| C++ 示例仅薄封装 | 直接 extern "C" 包含 C 头文件 |
8. Java 与 C 实现的同步
Java 和 C 实现通过以下方式保持一致性:
- 协议帧格式:DataHeader、StatusMessage、NAK 等帧结构在 Java(
protocol/*.java)和 C(protocol/aeron_udp_protocol.c)中独立定义,但字段偏移和大小严格一致 - CNC 文件布局:
CncFileDescriptor在 Java 和 C 中独立定义 - LogBuffer 元数据偏移:每个字段的偏移量在两端保持一致
- 版本号:
version.txt统一定义,Java 和 C 构建时分别读取
9. 关键源文件索引
C Client
| 文件 | 说明 |
|---|---|
| aeronc.h | C 客户端公开 API 头文件 |
| aeron_client.c | Client 主实现 |
| aeron_publication.c | Publication 实现 |
| aeron_subscription.c | Subscription 实现 |
| aeron_client_conductor.c | 客户端协调器 |
| aeron_atomic.c | 原子操作封装 |
C Driver
| 文件 | 说明 |
|---|---|
| aeronmd.h | C 驱动公开 API 头文件 |
| aeron_driver.c | Driver 主入口 |
| aeron_driver_conductor.c | 驱动协调器 |
| aeron_driver_sender.c | 发送器 |
| aeron_driver_receiver.c | 接收器 |
| aeron_flow_control.c | 流控 |