Go 粘包
Posted staff
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 粘包相关的知识,希望对你有一定的参考价值。
解决粘包:
用前4个字节存数据的长度, 剩下的字节存数据
( 大端和小端:数据存取和读取的顺序
16进制数:0x123456 占用3个字节
协议用4字节存数据长度
12 34 56 00 大端,高位在左边
00 56 34 12 小端 ,高位在右边)
// socket_stick/proto/proto.go
package protoimport (
"bufio"
"bytes"
"encoding/binary"
)// Encode 将消息编码
func Encode(message string) ([]byte, error) {
// 读取消息的长度,转换成int32类型(占4个字节)
var length = int32(len(message)) // 计算msg长度,放入4字节int中
var pkg = new(bytes.Buffer)
err := binary.Write(pkg, binary.LittleEndian, length) // 写入msg长度。小端的方式存放
if err != nil {
return nil, err
}
err = binary.Write(pkg, binary.LittleEndian, []byte(message)) // 写入消息实体。
if err != nil {
return nil, err
}
return pkg.Bytes(), nil
}// Decode 解码消息
func Decode(reader *bufio.Reader) (string, error) {
// 读取消息的长度
lengthByte, _ := reader.Peek(4) // 读取前4个字节byte,存放的是数据长度
lengthBuff := bytes.NewBuffer(lengthByte)
var length int32
err := binary.Read(lengthBuff, binary.LittleEndian, &length) // 将4个字节的byte,转为int32,放入length,length是数据长度
if err != nil {
return "", err
}
if int32(reader.Buffered()) < length+4 { // 如果reader总长度<4报错
return "", err
}// 读取真正的消息数据
pack := make([]byte, int(4+length)) // 在reader中读取length+4长度的字节(length是数据的长度)
_, err = reader.Read(pack)
if err != nil {
return "", err
}
return string(pack[4:]), nil
}
服务端:
// socket_stick/server2/main.go
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
msg, err := proto.Decode(reader)
if err == io.EOF {
return
}
if err != nil {
fmt.Println("decode msg failed, err:", err)
return
}
fmt.Println("收到client发来的数据:", msg)
}
}func main() {
listen, err := net.Listen("tcp", "127.0.0.1:30000")
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
go process(conn)
}
}
客户端:
// socket_stick/client2/main.go func main() { conn, err := net.Dial("tcp", "127.0.0.1:30000") if err != nil { fmt.Println("dial failed, err", err) return } defer conn.Close() for i := 0; i < 20; i++ { msg := `Hello, Hello. How are you?` data, err := proto.Encode(msg) if err != nil { fmt.Println("encode msg failed, err:", err) return } conn.Write(data) } }
以上是关于Go 粘包的主要内容,如果未能解决你的问题,请参考以下文章
[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础
解决go: go.mod file not found in current directory or any parent directory; see ‘go help modules‘(代码片段