[TOC] ## 不考虑 TCP 粘包 <details> <summary>server.go</summary> ``` // 定义协议 type Pack struct { Length uint32 Order uint64 SecretKey1 uint8 SecretKey2 uint8 Cmd uint16 StaticCode uint16 //0-正常 1-出错 2-命令未完成 0x000 3-命令需要ack Encryption uint8 // 0-误操作 1-AES256 2-国产sm4 Reserv uint32 //随机值 DataPack []byte //数据包的长度 } func NewPack(Cmd uint16,DataPack []byte) *Pack { Length :=uint32(4+8+1+1+2+2+1+4+len(DataPack)) return &Pack{ Length: Length, Order: 0x0010, SecretKey1: 0x10, SecretKey2: 0x01, Cmd: Cmd, StaticCode: 0, Encryption: 0, Reserv: 0, DataPack: DataPack, } } func (p *Pack) pack(writer io.Writer)error{ var err error err = binary.Write(writer,binary.BigEndian,&p.Length) err = binary.Write(writer,binary.BigEndian,&p.Order) err = binary.Write(writer,binary.BigEndian,&p.SecretKey1) err = binary.Write(writer,binary.BigEndian,&p.SecretKey2) err = binary.Write(writer,binary.BigEndian,&p.Cmd) err = binary.Write(writer,binary.BigEndian,&p.StaticCode) err = binary.Write(writer,binary.BigEndian,&p.Encryption) err = binary.Write(writer,binary.BigEndian,&p.Reserv) err = binary.Write(writer,binary.BigEndian,&p.DataPack) return err } func (p *Pack) UnPack(reader io.Reader)error{ var err error err = binary.Read(reader,binary.BigEndian,&p.Length) err = binary.Read(reader,binary.BigEndian,&p.Order) err = binary.Read(reader,binary.BigEndian,&p.SecretKey1) err = binary.Read(reader,binary.BigEndian,&p.SecretKey2) err = binary.Read(reader,binary.BigEndian,&p.Cmd) err = binary.Read(reader,binary.BigEndian,&p.StaticCode) err = binary.Read(reader,binary.BigEndian,&p.Encryption) err = binary.Read(reader,binary.BigEndian,&p.Reserv) p.DataPack=make([]byte,p.Length-(4+8+1+1+2+2+1+4)) err = binary.Read(reader,binary.BigEndian,&p.DataPack) return err } func (p *Pack) String() string { return fmt.Sprintf("%+v\n", p) } func main() { //pack 协议 接头体转字节流 pack := NewPack(0x12, []byte("param1 param2 \nProp1:asdsadasd\nProp2:asdasd")) fmt.Printf("%+v\n",*pack) // {Length:66 Order:16 SecretKey1:16 SecretKey2:1 Cmd:18 StaticCode:0 Encryption:0 Reserv:0 DataPack:[112 97 114 97 109 49 32 112 97 114 97 109 50 32 10 80 114 111 112 49 58 97 115 100 115 97 100 97 115 100 10 80 114 111 112 50 58 97 115 100 97 115 100]} buf :=new(bytes.Buffer) e := pack.pack(buf) if e != nil { panic(e) } fmt.Printf("%+v\n", buf.Bytes()) // [0 0 0 66 0 0 0 0 0 0 0 16 16 1 0 18 0 0 0 0 0 0 0 112 97 114 97 109 49 32 112 97 114 97 109 50 32 10 80 114 111 112 49 58 97 115 100 115 97 100 97 115 100 10 80 114 111 112 50 58 97 115 100 97 115 100] // unpack 协议 字节流转结构体 pack2 := new(Pack) e = pack2.UnPack(buf) if e != nil { panic(e) } fmt.Printf("%+v\n",*pack2) // {Length:66 Order:16 SecretKey1:16 SecretKey2:1 Cmd:18 StaticCode:0 Encryption:0 Reserv:0 DataPack:[112 97 114 97 109 49 32 112 97 114 97 109 50 32 10 80 114 111 112 49 58 97 115 100 115 97 100 97 115 100 10 80 114 111 112 50 58 97 115 100 97 115 100]} } ``` </details> <br/> ## 考虑 TCP 粘包 > [参考](https://segmentfault.com/a/1190000013493942) **目录结构** ``` ├── base │ └── struct.go └── run ├── server.go └── client.go ``` <details> <summary>base /struct.go</summary> ``` /** 协议示例: \x00\x00\x01\x14\x00\x00\x00\x01\x01\x00\x08\x00\x00\x00\x00 chenpp yuming 1 KTtiV2A+MgyyQNLYClF9gw== 2 2048 5.2.61 1 clientver:5.2.61 hostname: macaddr:74-D4-35-DD-AD-F700-FF-C2-85-08-42 opdata: optype: platform:1 smscode: status:0 */ //包头长度 const HAND_BODY = 16 type Ext struct { Params []string Prop []string } // 定义协议 type Pack struct { Length int32 // Ext 的长度 4个字节 Order int32 // 序号 SecretKey1 int8 // 随机秘钥1 SecretKey2 int8 // 随机秘钥2 Cmd int16 // cmd 命令 如 0x0008=为登录 0x0008=登出 StaticCode int8 // 状态 0-正常 1-出错 2-命令未完成 0x000 3-命令需要ack Encryption int8 // 加密: 0-误操作 1-AES256 2-国产sm4 Reserv int16 // 随机值 Body []byte // 数据包的长度 Ext Ext } func NewPack(Cmd int16, ext Ext) *Pack { var str string str =strings.Join(ext.Params," ") str +="\n" str +=strings.Join(ext.Prop,"\n") bufferString := bytes.NewBufferString(str) Length := HAND_BODY + int32(len(bufferString.Bytes())) log.Printf("%v",Length) return &Pack{ Length: Length, Order: 0x0010, SecretKey1: 0x10, SecretKey2: 0x01, Cmd: Cmd, StaticCode: 0x00, Encryption: 0x00, Reserv: 0x000, Body: bufferString.Bytes(), Ext: ext, } } // Pack 的值赋值给 writer func (p *Pack) Pack(writer io.Writer) error { var err error err = binary.Write(writer, binary.BigEndian, &p.Length) err = binary.Write(writer, binary.BigEndian, &p.Order) err = binary.Write(writer, binary.BigEndian, &p.SecretKey1) err = binary.Write(writer, binary.BigEndian, &p.SecretKey2) err = binary.Write(writer, binary.BigEndian, &p.Cmd) err = binary.Write(writer, binary.BigEndian, &p.StaticCode) err = binary.Write(writer, binary.BigEndian, &p.Encryption) err = binary.Write(writer, binary.BigEndian, &p.Reserv) err = binary.Write(writer, binary.BigEndian, &p.Body) return err } // pack的值复制给 reader func (p *Pack) UnPack(reader io.Reader) error { var err error err = binary.Read(reader, binary.BigEndian, &p.Length) err = binary.Read(reader, binary.BigEndian, &p.Order) err = binary.Read(reader, binary.BigEndian, &p.SecretKey1) err = binary.Read(reader, binary.BigEndian, &p.SecretKey2) err = binary.Read(reader, binary.BigEndian, &p.Cmd) err = binary.Read(reader, binary.BigEndian, &p.StaticCode) err = binary.Read(reader, binary.BigEndian, &p.Encryption) err = binary.Read(reader, binary.BigEndian, &p.Reserv) p.Body = make([]byte, p.Length-HAND_BODY) err = binary.Read(reader, binary.BigEndian, &p.Body) return err } func (p *Pack) ParseBody() Ext { b := string(p.Body) s := strings.Split(b, "\n") p.Ext.Params =strings.Split(s[0]," ") p.Ext.Prop=s[1:] return p.Ext } func (p *Pack) String() string { return fmt.Sprintf("%+v\n", *p) } ``` </details> <br/> <details> <summary>run/server.go</summary> ``` func main() { log.SetFlags(log.LstdFlags|log.Lshortfile) listener, e := net.Listen("tcp", ":9080") if e != nil { panic(e) } defer listener.Close() for { conn, e := listener.Accept() fmt.Printf("%+v\n", conn.RemoteAddr()) if e != nil { log.Printf("%s", e) continue } go Read(conn) } } func Read(conn net.Conn) { byt := make([]byte, 2048) buf := new(bytes.Buffer) for { n, err := conn.Read(byt) if err != nil { continue } buf = bytes.NewBuffer(byt[:n]) scanner := bufio.NewScanner(buf) scanner.Split(split) for scanner.Scan() { scannedPack := new(base.Pack) _=scannedPack.UnPack(bytes.NewReader(scanner.Bytes())) log.Println(scannedPack) scannedPack.ParseBody() fmt.Printf("%+v\n", scannedPack.Ext) } if err := scanner.Err(); err != nil { log.Printf("无效数据包") continue } } } //拆包 func split(data []byte, atEOF bool) (advance int, token []byte, err error) { if !atEOF { if len(data) > base.HAND_BODY { // or >4 length := int32(0) _=binary.Read(bytes.NewReader(data[:4]), binary.BigEndian, &length) return int(length), data[:length], nil } } return } ``` </details> <br/> <details> <summary>run/client.go</summary> ``` func main() { ext := base.Ext{} ext.Params=[]string{"chenpj2","aip","KTtiV2A+MgyyQNLYClF9gw","2","2048","5.2.61","1"} ext.Prop=[]string{"clientver:5.2.61","platform:1","hostname:","macaddr74-D4-35-DD-AD-F7,BC-9D-A5-70-27-A8,00-50-56-C0-00-08,7E-15-5B-7E-AB-85,00-15-5D-2F-91-00,00-FF-72-86-02-D7,00-FF-C2-85-08-42","opdata:","optype:","smscode:","status:"} pack := base.NewPack(0x01, ext) conn, e := net.Dial("tcp", ":9080") if e != nil { panic(e) } defer conn.Close() buf :=new(bytes.Buffer) e = pack.Pack(buf) if e != nil { log.Printf("%v",e) } log.Printf("%+v\n", buf.Bytes()) conn.Write(buf.Bytes()) time.Sleep(2*time.Second) } ``` </details> <br/> **启动** ``` go run server.go go run client.go ```