目前正在测试中:完成后将开放 GitHub 代码。

传输层

项目
传输方式TCP(持久连接)
默认端口5225
Socket 选项启用 TCP_NODELAY —— 立即发送小数据包,不受 Nagle 合并延迟影响
TLS可选 —— 如果服务器配置了证书,整条连接会被包裹在单向 TLS(服务器认证)中
编码定宽二进制字段 + UTF-8 key。整数采用大端序(网络字节序)
帧终止符一个 \n 字节。不处理 \r
空帧单独的 \n(op 位置为 \n)会被静默忽略,视为保活(keep-alive)
最大帧大小192字节——包含op,不含\n(超限 → E line_too_long关闭连接
流水线 (Pipelining)允许 —— 响应到达顺序可能与请求顺序不同
空闲超时无 —— 服务器不会主动关闭静默连接
帧进度时间从收到op首个byte到fixed header与LF最多5秒;部分发送不能无限占用connection

连接建立顺序

  1. TCP 连接
  2. 如果服务器启用了 TLS,则进行 TLS 握手 —— 以明文连接启用了 TLS 的服务器会在 此步骤断开
  3. 认证握手,仅执行一次
  4. 此后开始交换锁协议帧

分帧规则

每条消息就是一帧 = 一行。

[ op: 1 字节 ][ op 专属定长头部 ][ 变长正文 ] \n

接收方必须先查看 op,按其字节数先读取定长头部,之后才扫描 \n。 这是因为定长头部是二进制数据,可能包含值恰好为 0x0A(\n)的字节 (例如 lease=100A)。\n 扫描仅适用于末尾的 key/文本部分。

方向op定长头部
客户端 → 服务器A10 bytes (wait:u8 + lease:u8 + owner:u64 BE)
客户端 → 服务器R8 bytes (token:u64 BE)
服务器 → 客户端A16 bytes (token:u64 BE + owner:u64 BE)
服务器 → 客户端T · B8 bytes (owner:u64 BE)
服务器 → 客户端R · N8 bytes (token:u64 BE)
服务器 → 客户端M · L · E0 bytes (address/reason UTF-8 text)

frame超过192 bytes或malformed时,服务器尽可能flush E关闭连接。客户端也把malformed、oversized、未知op或无法关联的E视为connection-fatal。该session中已发送至少一个byte的acquire不自动重试;若无确定响应则为Indeterminate

术语

  • 帧 (Frame) —— 将连续的字节流(TCP)切分成"一条消息"的单位。在本协议中, 一个以 \n 结尾的行就是一帧。
  • 大端序 (Big-endian) —— 先写入整数最高有效字节的字节序。这是网络协议的 标准做法,因此也称为网络字节序。
  • 流水线 (Pipelining) —— 无需等待上一个响应即可发送下一个请求。通过这种 方式重叠往返延迟可以提升吞吐量。
  • 保活 (Keep-alive) —— 周期性发送的、用于宣告连接仍然存活的无意义信号。 在这里,空帧(\n)承担了这一角色。