作为读取消息的服务器,您如何找出消息的长度?

As a server that reads a message, how do you find out its length?

我正在编写一个服务器,它接受来自客户端的传入连接,然后从中读取(通过 net.Conn.Read())。显然,我会将消息读入 []byte 切片,然后以不相关的方式对其进行处理,但问题是 - 我如何首先找出此消息的长度以创建相应长度的切片?

这完全取决于您尝试从连接中读取的协议的设计。

如果您正在设计自己的协议,则需要为您的 reader 设计一些方法来确定何时停止阅读或预先声明消息的长度。

对于二进制协议,您经常会发现某种固定大小header,其中包含一个length值(例如,一个big-endian int64) 在一些 known/discoverable header 偏移处。然后,您可以解析 length 偏移量处的值,并在到达可变长度数据开始的偏移量后使用该值读取正确数量的数据。二进制协议的一些示例包括 DNSHTTP/2.

对于文本协议,何时停止阅读将在解析规则中进行编码。文本协议的一些示例包括 HTTP/1.xSMTP。例如,HTTP/1.1 请求将协议声明为:

METHOD /path HTTP/1.1\r\n
Header-1: value\r\n
Header-2: value\r\n
Content-Length: 20\r\n
\r\n
This is the content.

第一行(表示以 \r\n 结尾的行)必须包含 HTTP 方法,后跟路径(可以是绝对路径或相对路径),然后是版本。

后续行定义为 headers,由键和值组成。

键包括从行首到冒号的任何文本,但不包括冒号。冒号后是可变数量的无关紧要的 space 个字符,后跟值。

其中一个 header 是特殊的,表示即将到来的 body 的长度:Content-Length。此 header 的值包含要作为 body 读取的字节数。对于我们的简单情况(忽略尾部、分块编码等),我们将假设 body 的结尾表示请求的结尾,另一个请求可能紧随其后。

在最后一个 header 之后是一个空行,表示 header 块的结尾和 body (\r\n\r\n) 的开头。

一旦你读完所有的headers,你就可以从你解析的Content-Lengthheader中获取值,并读取与其值对应的下一个字节数。

有关更多信息,请查看:

最后我做的是创建一个 1024 字节的切片,然后从连接中读取消息,然后将切片缩短为读取的整数数。

选择正确的解决方案不好。如果消息超过 1024 字节会怎样?如果您没有不同类型的消息,则需要 TLV(类型长度值)或 LV 形式的协议。例如,Type 可以是 2 Bytes,Length 可以是 2 Bytes。然后你总是先读4个Bytes,然后根据Bytes 2和3指示的长度,你就知道后面来了多少Bytes,然后你再读剩下的。您还需要考虑其他事项:TCP 是面向流的,因此为了读取完整的 TCP 消息,您可能需要多次读取。阅读这个(它适用于 Java 但对任何语言都有用):How to read all of Inputstream in Server Socket JAVA