我无法理解使用固定大小前缀长度标头的消息框架是如何工作的。据说一个固定大小的字节数组将包含要发送的消息的长度。但是你将如何定义一个固定大小的字节数组,特别是在 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 } } }}
1 回答
炎炎设计
TA贡献1808条经验 获得超4个赞
请参考我在这篇文章中的回答 TCP client for Android: text is not received full
基本上,您必须定义数据如何存储/格式化。例如:
我们将前缀长度存储为
int32
(4 字节),小端。它和你的不一样。使用您的解决方案,长度是 a
string
,很难确定长度。对于您的解决方案,您必须使用固定长度的字符串。例如:10 个字符,并添加前导零。
对于您的问题。
它不适用于只有前缀长度的所有情况。它有它的局限性,例如如果我们使用
int32
前缀长度,消息的长度必须小于 Integer32.max,对吗?是的,我们必须拆分甚至合并(请参阅我在上面链接中的解释)。
如果这是我们关心的问题,我们有很多方法来处理长度限制(实际上,几乎应用程序协议都有最大请求大小)。您可以多用一位来指示消息是否超过最大长度来解决它,对吗?
- 1 回答
- 0 关注
- 177 浏览
添加回答
举报
0/150
提交
取消