Skip to content

C++ 客户端接入

本文档面向 C++ 客户端开发者,说明如何使用 cxx/ 目录提供的 zezecxx 库实现二进制序列化、网络连接管理与协议编解码,与 Zeze Java 服务端完成通信。

cxx/ 目录提供与 Zeze Java 服务端通信的完整能力,包含二进制序列化、网络连接管理、协议编解码等模块,编译后产出静态库 zezecxx.a。该库适用于原生 C++ 游戏客户端或服务,序列化格式与 Java / C# / TypeScript 客户端完全一致,保证跨语言互操作。

cxx/ 目录主要源文件及其职责:

文件说明
ByteBuffer.h / ByteBuffer.cpp二进制编解码核心。
Net.h / Net.cpp网络层,包含 Socket / Service / Selector(基于 epoll / kqueue / wepoll)。
Protocol.h / Protocol.cpp协议基类,负责编解码与派发。
Rpc.hRPC 模板,支持异步与超时。
Bean.hBean 基类(EmptyBeanDynamicBean)。
Vector.hVector2 / Vector3 / Vector4 / Quaternion
security.h / security.cppAES 加密。
rfc2118.h / rfc2118.cppMPPC 压缩。
dh.h / dh.cppDH 密钥交换。

Zeze::ByteBuffer 提供基础读写接口。

Zeze::ByteBuffer bb(256);
// 写入
bb.WriteBool(true);
bb.WriteInt(42); // 1-9 字节变长
bb.WriteLong(123456789LL); // 1-9 字节变长
bb.WriteString("hello");
bb.WriteFloat(3.14f);
// 读取
bool b = bb.ReadBool();
int i = bb.ReadInt();
int64_t l = bb.ReadLong();
std::string s = bb.ReadString();
float f = bb.ReadFloat();

固定长度接口:

接口说明
WriteInt4 / ReadInt4固定 4 字节,用于协议头。

每个 Bean 字段使用 1 字节 Tag 编码:

  • 高 4 位:字段类型常量。
  • 低 4 位:字段 ID 增量(相对上一个字段的差值)。

ByteBuffer 使用的类型常量:

常量类型
INTEGER0整数
FLOAT1单精度浮点
DOUBLE2双精度浮点
BYTES3二进制
LIST4列表
MAP5映射
BEAN6Bean
DYNAMIC7动态 Bean
VECTOR28二维向量(float)
VECTOR2INT9二维向量(int)
VECTOR310三维向量(float)
VECTOR3INT11三维向量(int)
VECTOR412四维向量(float,亦用于 Quaternion)

SkipUnknownField 用于跳过未知字段,保证协议升级时的前向兼容性。

Zeze::Net::Startup(); // 全局初始化
// ... 业务逻辑 ...
Zeze::Net::Cleanup(); // 全局清理

Service 负责连接管理与协议派发:

// 注册协议工厂(类型 ID + 工厂 + 处理器)
service.AddProtocolFactory(typeId, ProtocolFactoryHandle{factory, handler});
// 主动连接(地址、端口、超时秒)
service.Connect("127.0.0.1", 8080, 5);
// 监听(必须传 host 和 port,非无参)
service.Listen("::", 7777); // 返回 std::string

连接建立后进行握手,可配置加密与压缩选项:

// 加密类型、压缩类型
service.SetHandshakeOptions(eEncryptTypeAesNoSecureIp,
eCompressTypeMppc,
eCompressTypeDisable);
选项说明
eEncryptTypeAesNoSecureIpAES 加密,不校验 IP 安全性。
eCompressTypeMppc启用 MPPC 压缩。
eCompressTypeDisable禁用压缩。
// 检查周期、发送超时、接收超时(秒)
service.SetKeepConfig(10, 25, 60);
参数说明
检查周期心跳检测的触发间隔(10 秒)。
发送超时发送心跳后等待确认的超时(25 秒)。
接收超时长时间未接收数据的超时(60 秒)。

自定义协议需继承 ProtocolWithArgument<MyArgument>,并实现模块号与协议号:

class MyProtocol : public Zeze::Net::ProtocolWithArgument<MyArgument> {
public:
static constexpr int ModuleId() { return 1; }
static constexpr int ProtocolId() { return 100; }
// TypeId 与 Java 端完全一致
static constexpr int64_t TypeId() {
return ((int64_t)ModuleId() << 32) | (unsigned)ProtocolId();
}
};

关键约定TypeIdModuleIdProtocolId 组合而成,定义方式与 Java 服务端完全一致,确保跨语言协议匹配。

MyRpc rpc;
rpc.Argument->setValue(42);
// 异步发送:Socket、回调、超时(毫秒)
rpc.SendAsync(socket, [](MyRpc* r) {
// 处理返回结果
}, 5000);
Terminal window
cd cxx/
make all # 编译产出 zezecxx.a
make clean # 清理

编译要求:C++11、优化级别 -O2、链接 -pthread

通过以下头文件提供 Lua 绑定支持:

  • ToLua.h
  • ToLuaService.h

按以下步骤完成接入:

  1. 引入库:将 cxx/ 源文件加入项目,或链接预编译的 zezecxx.a
  2. 初始化:调用 Startup() / Cleanup() 进行全局初始化与清理。
  3. 注册协议:继承 Service,注册所需协议工厂与处理器。
  4. 连接 Linkd:调用 Connect() 建立与服务端的连接。
  5. 业务通信:在 OnHandshakeDone 回调后开始收发业务数据。
  6. 参考序列化:确保编解码字段顺序与格式一致。