什么是粘包,为什么会有粘包处理
tcp (transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的 socket ,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的
处理方法
一般有两种处理方式,一种为发送数据流用分隔符,另一种在客户端发包的时候定义包体的长度,服务端按照一定的规则解包
栗子-client
package main import ( " bytes " " encoding /binary" "fmt" "net" "os" ) type PackageHeader struct { ServiceID uint32 // service id Command uint32 // operation Command code Code int32 // error code Len uint16 // body length } type Package struct { H PackageHeader B string } func (p Package) Marshal() (* byte s. Buffer , error) { var ( err error buf *bytes.Buffer ) buf = &bytes.Buffer{} err = binary.Write(buf, binary.LittleEndian, p.H) if err != nil { return nil, err } buf.WriteByte((byte)(len(p.B))) buf.WriteString(p.B) return buf, nil } func main() { server := "127.0.0.1:9988" for i := 0; i < 100; i++ { tcpAddr, err := net.ResolveTCPAddr("tcp4", server) if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } body := "abcdedfesabcdedfesabcdedfesabcdedfesabcdedfesabcdedfesabcdedfesabcdedfesabcdedfesAAAA" pkg := Package{} pkg.B = body pkg.H = PackageHeader{ ServiceID:1, // service id Command:1, // operation command code Code :1, // error code Len: uint16(len(pkg.B)) + 1, // body length } buffer,err := pkg.Marshal() if err != nil { fmt.Println(err.Error()) } else { conn.Write(buffer.Bytes()) } conn. Close () } }