我无法理解使用固定大小前缀长度标头的消息框架是如何工作的。
据说一个固定大小的字节数组将包含要发送的消息的长度。但是你将如何定义一个固定大小的字节数组,特别是在 Golang 中。
说这是我的信息:
Hello
它的长度是 5。
因此,如果我想通过 tcp 流发送它,为了确保我在另一端收到所有消息,我必须告诉它应该读取多少字节。
一个简单的标题是length:message:
5:Hello // [53 58 104 101 108 108 111]
但是如果消息长度每次增长 10 倍,就会有更多的字节。所以标题大小是动态的。
36:Hello, this is just a dumb question. // [51 54 58 72 101 108 108 111 44 32 116 104 105 115 32 105 115 32 106 117 115 116 32 97 32 100 117 109 98 32 113 117 101 115 116 105 111 110 46]
所以这里36需要2个字节。
我想到的一种方法是考虑协议的最大消息长度。假设 10KB = 10240 字节。然后将前导添加0到消息长度。这样,我确定我将拥有一个固定的 5 字节标头。
这适用于所有情况吗?
如果是,如果我有超过 10KB 的消息,我应该将其拆分为 2 条消息吗?
如果不是,还有什么其他解决方案?
我想在 Golang 中实现解决方案。
更新 1:
我读过关于 Endians 的文章,尽管我无法理解他们做了什么会导致固定长度的字节。但是我在python中找到了一个示例,并尝试以这种方式编写它:
客户:
const maxLengthBytes = 8
conn, err := net.Dial("tcp", "127.0.0.1:9999")
if err != nil {
fmt.Println(err)
return
}
message := "Hello, this is just a dumb question"
bs := make([]byte, maxLengthBytes)
binary.LittleEndian.PutUint64(bs, uint64(len(text)))
bytes := append(bs, []byte(text)...)
conn.Write(bytes)
服务器:
listener, err := net.ListenTCP("tcp", &net.TCPAddr{Port: 9999})
if err != nil {
fmt.Println(err)
return
}
for {
tcp, err := listener.AcceptTCP()
if err != nil {
fmt.Println(err)
continue
}
go Reader(tcp)
}
func Reader(conn *net.TCPConn) {
foundLength := false
messageLength := 0
for {
if !foundLength {
var b = make([]byte, maxLengthBytes)
read, err := conn.Read(b)
if err != nil {
fmt.Println(err)
continue
}
if read != 8 {
fmt.Println("invalid header")
continue
}
}
}
}
炎炎设计
相关分类