#协议 #请求 #序列化 # #错误 #agilulf #服务器

nightly agilulf_protocol

Agilulf协议序列化和反序列化器

1 个不稳定版本

0.1.0 2019年7月19日

#1704 in 异步


3 个crate 中使用

MIT 许可证

30KB
606

Agilulf KV协议

本协议的设计借鉴了Redis协议。但由于这个KV服务器不提供如此复杂的数据结构,因此协议更为简单。

本协议可用于TCP流。因为它不处理传输错误,也不提供任何正确性的保证(通过校验和或其他技术),因此您必须提供稳定且安全的传输层(TCP在这方面相当出色。也许QUIC或KCP可以提供更好的性能)

由于简洁性是本项目的首要指导原则,此crate仅实现了在TCP流上的序列化和反序列化。但通过此crate中的一些辅助函数(目前是私有的),将此协议绑定到其他传输层并不困难。此crate提供了接口以接受任何AsyncWrite + UnpinAsyncRead + Unpin,并将它们转换为Stream<Command>Sink<Reply>。Agilulf KV服务器旨在使用最新的rust async/await功能,因此使用来自futures crate的StreamSink作为接口。

请求-响应模型

服务器对来自客户端的每个请求都做出响应。但是,客户端可以同时发送多个请求并等待它们的响应。在这种情况下,响应的顺序将与请求的顺序一致。

请求

此crate按照以下步骤反序列化请求

1. 检查第一行(以\r\n结尾)是否为"*"+数字。此数字提供了有关消息中有多少部分的信息。

  1. 对于每个部分,它以“$”+数字开始。这个数字提供了有关该部分内容长度信息。

  2. 然后我们得到一个部分列表。可以轻松地从它们中读取命令。

示例

  1. 简单的PUT请求
*3
$3
PUT
$5
HELLO
$5
WORLD

注意:示例中的每一行都通过\r\n分隔,因此上面的请求实际上是*3\r\n$3\r\nPUT\r\n$5HELLO\r\n$5WORLD

  1. 简单的GET请求
*2
$3
GET
$5
HELLO
  1. 删除请求
*2
$6
DELETE
$5
HELLO
  1. 扫描请求
*3
$4
SCAN
$1
A
$6
AAAAAA

注意

此协议允许将任何二进制存储在内容中(键和值)。因为它为每个部分提供了长度,所以它永远不会解码每个部分的内容,而只是简单地将其复制到RAM中。

响应

响应非常简单。此协议不针对每种请求类型提供响应格式,而只提供一些简单的格式(对于KV服务器来说足够了)。只有四种类型的响应

  1. 状态。响应将以“+”开头,后跟状态消息。例如,“+OK”表示此请求操作成功。PUT请求和DELETE请求可能会导致此类型的响应。

  2. 错误。此类型的响应将以“-”开头,后跟错误消息。例如,“-KeyNotFound”表示找不到错误。GET一个不存在的键(或已删除的键)将导致此。

  3. 一个片段。它以第一行“$”+数字开始。这里的数字告诉客户端片段有多长。然后是响应的内容。例如,一个简单的GET请求可能以“$5\r\nWORLD\r\n”响应。

  4. 多个片段。它以第一行“*”+数字开始。这个数字告诉客户端它包含多少个片段。然后对于每个片段,协议与单个片段格式相同。例如,SCAN请求可能以“*1\r\n$5\r\nWORLD\r\n”响应。

接口设计

数据流如下所示:TcpStream -> Stream<Command> -> Database -> Sink<Reply> -> TcpSink。这个crate将流的第一部分和最后一部分。它可以简单地将TcpStream转换为命令流,并将TcpSink转换为回复接收器。

使用此crate,实现Agilulf KV服务器只需要处理核心部分:将每个命令转换为回复(响应每个请求)。

注意:简单地将流传递到接收器将不会工作。需要recv和send循环。很抱歉,我不知道为什么会出现这种情况。当我尝试使用send_all将它们一起传递时,我注意到我的Sink<Reply>已经接收并处理了回复,但它从未发送出去。

依赖关系

~5.5MB
~110K SLoC