在开发 Socket 通信时,由于 TCP 协议的特性,在网络状况不佳的情况下,数据传输过程中经常会出现半包或粘包。为解决这一问题,通常我们需要自定义一个通信协议,增加一个 HEADER 部分,并在其中对数据包的长度进行声明,下面分享一段封包和解包的示例代码,可用于 Golang 开发 Socket 时处理数据传输,具体代码如下:
package protocol import ( "bytes" "encoding/binary" ) const ( TCP_HEADER = "TCPHEADER" TCP_HEADER_LEN = 9 TCP_DATA_LEN = 4 ) // 封包 func Enpack(msg []byte) []byte { return append(append([]byte(TCP_HEADER), IntToBytes(len(msg))...), msg...) } // 解包 func Depack(buffer []byte, readerChannel chan []byte) []byte { length := len(buffer) var i int for i = 0; i < length; i++ { if length < i + TCP_HEADER_LEN + TCP_DATA_LEN { break } if string(buffer[i:i + TCP_HEADER_LEN]) == TCP_HEADER { msgLen := BytesToInt(buffer[i + TCP_HEADER_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN]) if length < i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen { break } data := buffer[i + TCP_HEADER_LEN + TCP_DATA_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen] readerChannel <- data i += TCP_HEADER_LEN + TCP_DATA_LEN + msgLen - 1 } } if i == length { return make([]byte, 0) } return buffer[i:] } // 整形转换成字节 func IntToBytes(n int) []byte { x := int32(n) bytesBuffer := bytes.NewBuffer([]byte{}) binary.Write(bytesBuffer, binary.BigEndian, x) return bytesBuffer.Bytes() } // 字节转换成整形 func BytesToInt(b []byte) int { bytesBuffer := bytes.NewBuffer(b) var x int32 binary.Read(bytesBuffer, binary.BigEndian, &x) return int(x) }