SoupBinTCP
版本 3.00
更新日期:2017年2月22日
1. 概述
SoupBinTCP 是一个轻量级的点对点协议,构建在 TCP/IP 套接字之上,允许从服务器向客户端实时传递一组有序消息。SoupBinTCP 保证客户端按顺序接收服务器生成的每条消息,即使在底层 TCP/IP 套接字连接失败时也是如此。
SoupBinTCP 客户端可以向服务器发送消息。这些消息不是有序的,在 TCP/IP 套接字故障的情况下可能会丢失。
对于需要服务器向客户端实时传递逻辑流的有序消息但不需要同样级别的客户端生成消息保证的系统,SoupBinTCP 是理想的选择,因为数据流是单向的,或者因为服务器应用程序生成了更高级别的有序确认以确认任何重要的客户端生成消息。
SoupBinTCP 设计用于与更高级别的协议一起使用,这些协议指定了 SoupBinTCP 消息传递的消息内容。SoupBinTCP 协议层对更高级别的消息是透明的。注意,与 ASCII 版本不同,消息可能包含任何可能的字节。
SoupBinTCP 还包括一个简单的方案,允许服务器在登录时验证客户端。
1.1 SoupBinTCP 逻辑包
SoupBinTCP 客户端和服务器通过交换一系列逻辑包进行通信。
每个 SoupBinTCP 逻辑包具有:
A. 两个字节的大端长度,表示包其余部分的长度(即有效载荷的长度加上包类型的长度——即1)
B. 单个字节的头部,表示包类型
C. 可变长度的有效载荷
两字节包长 | 包类型 | 可变长度有效载荷
SoupBinTCP 逻辑包结构
注意:
SoupBinTCP 逻辑包不一定直接映射到底层网络套接字上的物理包;它们可能会被 TCP/IP 堆栈拆分或聚合。
SoupBinTCP 协议没有定义最大有效载荷长度。
与 ASCII 版本不同,有效载荷可能包含换行符或任何字符。
1.2 协议流程
SoupBinTCP 连接始于客户端打开一个 TCP/IP 套接字到服务器并发送一个登录请求包。如果登录请求有效,服务器将响应一个登录接受包并开始发送有序数据包。连接持续到 TCP/IP 套接字断开。
每个有序数据包携带一个更高级别协议消息。
有序数据包不包含显式的序列号;相反,客户端和服务器通过计算消息的数量本地计算序列号。
每个会话中第一个有序消息的序列号总是1。
通常,在最初登录服务器时,客户端将在登录请求包中将请求序列号字段设置为1,并将请求会话字段留空。客户端将检查登录接受包以确定当前活动的会话。从1开始,每次收到有序数据包时,客户端开始递增其本地序列号。如果 TCP/IP 连接中断,客户端可以重新登录服务器,指示当前会话及其下一个预期的序列号。通过这种方式,客户端保证始终按顺序接收每条有序消息,尽管 TCP/IP 连接失败。
SoupBinTCP 还允许客户端在收到登录接受包后随时使用无序数据包向服务器发送消息。这些消息可能会在 TCP/IP 套接字连接失败期间丢失。
1.3 心跳
SoupBinTCP 使用逻辑心跳包快速检测链路故障。服务器必须在最后一次发送任何数据后超过1秒时发送服务器心跳包。这确保客户端将定期接收数据。如果客户端在一段时间内没有收到任何数据(既没有数据也没有心跳),则可以假设链路已断开并尝试使用新的 TCP/IP 套接字重新连接。
类似地,一旦登录,客户端必须在最后一次发送任何数据后超过1秒时发送客户端心跳包。如果服务器在一段时间内(通常为15秒)没有收到客户端的任何消息,则可以关闭现有套接字并监听新的连接。
1.4 会话结束标志
服务器通过发送会话结束消息指示当前会话已终止。这表示在此会话中不会再有消息。
客户端将不得不重新连接并使用新的会话 ID 或空白(填充空格)的会话 ID 登录,以开始接收下一个可用会话的消息。
1.5 数据类型
字符数据字段是标准的 ASCII 字节。
整数字段是二进制大端值。
2. SoupBinTCP 包类型
2.1 调试包
调试包可以在 SoupBinTCP 连接的任意一端随时发送。调试包旨在提供可帮助调试问题的人类可读文本。调试包应被客户端和服务器应用软件忽略。
调试包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "+" | 调试包 |
| 文本 | 3 | 可变 | 字母数字 | 自由形式的人类可读文本 |
2.2 SoupBinTCP 服务器发送的逻辑包
2.2.1 登录接受包
SoupBinTCP 服务器在收到有效的客户端登录请求后发送登录接受包。此包将始终是服务器在成功登录请求后发送的第一个非调试包。
登录接受包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "A" | 登录接受包 |
| 会话 | 3 | 10 | 字母数字 | 当前登录会话的会话 ID,左填充空格 |
| 序列号 | 13 | 20 | 数字(ASCII) | 下一个要发送的有序消息的序列号,左填充空格 |
2.2.2 登录拒绝包
SoupBinTCP 服务器在收到无效的登录请求包后发送此包。服务器在发送登录拒绝包后关闭套接字连接。在登录尝试失败的情况下,登录拒绝包将是服务器发送的唯一非调试包。
登录拒绝包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "J" | 登录拒绝包 |
| 拒绝原因代码 | 3 | 1 | 字母 | 见下方的登录拒绝代码 |
登录拒绝代码
| 代码 | 解释 |
|---|---|
| "A" | 未授权。登录请求消息中的用户名和密码无效。 |
| "S" | 会话不可用。登录请求包中的请求会话无效或不可用。 |
2.2.3 有序数据包
有序数据包充当信封,携带从服务器传输到客户端的实际有序数据消息。每个有序数据包携带一个来自更高级别协议的消息。每个消息的序列号是隐含的;给定 TCP/IP 连接的第一个有序数据包的初始序列号在登录接受包中指定,序列号按每发送一个有序数据包递增1。
由于 SoupBinTCP 逻辑包是通过 TCP/IP 套接字传输的,逻辑包丢失的唯一方式是在 TCP/IP 套接字连接故障的情况下。在这种情况下,客户端可以重新连接到服务器并请求下一个预期序列号,并从中断的地方继续。
有序数据包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "S" | 有序数据包 |
| 消息 | 3 | 可变 | 任意 | 由更高级别协议定义 |
2.2.4 服务器心跳包
服务器在超过1秒未向客户端发送任何数据时应发送服务器心跳包。如果客户端在一段时间
内没有收到任何数据,可以假设链路已断开。
服务器心跳包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "H" | 服务器心跳包 |
2.2.5 会话结束包
服务器将发送会话结束包以表示当前会话已结束。连接将在此包发送后不久关闭,用户将无法重新连接到当前会话。
会话结束包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "Z" | 会话结束包 |
2.3 SoupBinTCP 客户端发送的逻辑包
2.3.1 登录请求包
SoupBinTCP 客户端必须在建立新的 TCP/IP 套接字连接到服务器后立即发送登录请求包。
客户端和服务器必须事先商定用户名和密码字段。它们提供简单的身份验证以防止客户端无意中连接到错误的服务器。
用户名和密码均不区分大小写,应在右侧填充空格。
如果服务器在合理时间内(通常为30秒)未收到登录请求包,则可以终止传入的 TCP/IP 套接字。
登录请求包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "L" | 登录请求包 |
| 用户名 | 3 | 6 | 字母数字 | 用户名 |
| 密码 | 9 | 10 | 字母数字 | 密码 |
| 请求会话 | 19 | 10 | 字母数字 | 指定客户端希望登录的会话,或全空白以登录当前活动的会话 |
| 请求序列号 | 29 | 20 | 数字(ASCII) | 指定客户端希望在连接时接收的下一个序列号,或为0以开始接收最近生成的消息 |
2.3.2 无序数据包
无序数据包充当信封,携带从客户端传输到服务器的实际数据消息。这些消息不是有序的,在套接字故障的情况下可能会丢失。更高级别的协议必须能够在 TCP/IP 套接字连接故障的情况下处理这些丢失的消息。
无序数据包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "U" | 无序数据包 |
| 消息 | 3 | 可变 | 任意 | 由更高级别协议定义 |
2.3.3 客户端心跳包
客户端在超过1秒未向服务器发送任何数据时应发送客户端心跳包。如果服务器在一段时间内没有收到任何数据,可以假设链路已断开。
客户端心跳包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 整数 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "R" | 客户端心跳包 |
2.3.4 注销请求包
客户端可以发送注销请求包以请求终止连接。服务器在收到注销请求包后将立即终止连接并关闭相关的 TCP/IP 套接字。
注销请求包
| 名称 | 偏移 | 长度 | 值 | 备注 |
|---|---|---|---|---|
| 包长度 | 0 | 2 | 二进制 | 此字段之后到下一个包的字节数 |
| 包类型 | 2 | 1 | "O" | 注销请求包 |
3. 支持
有关 SoupBinTCP 规范的任何问题应发送电子邮件至 devsupport@nasdaqomx.com。
4. 当前限制
无已知限制。
5. 修订历史
| 版本 | 日期 | 修订历史 |
|---|---|---|
| 1.0 | 1999/09/01 | 初始分发 |
| 2.0 | 2001/10/29 | 增加了双向心跳以消除对 TCP/IP 保持连接的依赖,以检测链路故障。现在服务器和客户端都保证至少每秒发送一次数据(无论是数据还是心跳)。这样,如果您在几秒钟内没有从套接字听到任何消息,您可以假定套接字已死并关闭它。添加了调试消息,因为它们在调试问题时很方便。例如,服务器在接受连接时发送调试消息,标识机器名称。这样,有人可以通过 TELNET 进入服务器并立即验证他们是否连接到正确的主机。为出站有序消息和入站无序消息添加“信封”,以将它们与心跳区分开来。 |
| 3.0 | 2008/10/15 | 初始分发 SoupBinTCP3.0,从 SoupTCP3.0 衍生。包长前缀为两字节而不是以换行符结束,但包类型相同。加宽了登录相关包上的序列号字段,以支持 10 亿条消息或更多的流。添加了明确的会话结束包,以便 SoupTCP 会话层代码可以更干净地检测到 SoupTCP 会话的结束。 |
| 3.0 | 2011/04/12 | 从有序数据包描述中删除了冲突的句子。 |
| 3.0 | 2014/03/20 | 添加了处理用户提交的下一个预期序列号超过服务器当前最高序列消息的场景的语言。 |
| 3.0 | 2017/02/22 | 修订了第 2.2.3 和 2.3.2 节中的消息字段。 |