基于TCP服务的TLV编解码
一、实现思路
- 实现一个tcp服务端和tcp客户端
- 通过TLV方式编解码
TLV分别为:标签域(Tag),长度域(Length),内容域(Value)。
二、实现代码
service_test.go
package server
import (
"errors"
"fmt"
"github.com/sea-project/sea-pkg/util/conv"
"io"
"net"
"testing"
)
const (
TypeLen = 1 // 2^8=256
LenLen = 2 // 2^16=65536
ContentMaxLen = 1024 * 64
BufLen = 1 + 2 + 1024*64
MsgText = uint8(66) // 文字信息
MsgImg = uint8(88) // 图片信息
)
func Test_TLVMain(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:8888")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
continue
}
fmt.Println("A client connected :" + conn.RemoteAddr().String())
go tcpPipe(conn)
}
}
func tcpPipe(conn net.Conn) {
bufData := make([]byte, BufLen)
var err error
var data []byte
for {
_, _ = io.ReadFull(conn, bufData)
if len(bufData) == 0 {
break
}
data, bufData, err = Unpack(bufData)
if err != nil {
conn.Close()
}
if len(data) == 0 {
break
}
var msgType string
if uint8(data[:1][0]) == 66 {
msgType = "文字消息:"
} else {
msgType = "图片消息:"
}
fmt.Println(msgType + string(data[1:]))
}
}
func Unpack(buf []byte) ([]byte, []byte, error) {
// 取出消息类型
t := uint8(buf[:1][0])
if t != 66 && t != 88 {
err := errors.New("消息类型错误")
return nil, nil, err
}
// 取出消息长度
l := conv.Bytes2uint16(buf[1:3])
data := buf[0 : l+3]
bufData := buf[l+3:]
return data, bufData, nil
}
client_test.go
package client
import (
"bytes"
"encoding/binary"
"github.com/sea-project/sea-pkg/util/time"
"net"
"testing"
)
const (
TypeLen = 1 // 2^8=256
LenLen = 2 // 2^16=65536
ContentMaxLen = 1024 * 64
BufLen = 1 + 2 + 1024*64
MsgText = uint8(66) // 文字信息
MsgImg = uint8(88) // 图片信息
)
func Test_TLVMain2(t *testing.T) {
conn, _ := net.Dial("tcp", "127.0.0.1:8888")
for i := 0; i < 100; i++ {
currTime := time.GetUnixToFormatString(time.CurrentSecond(), "2006-01-02 15:04:05")
data := []byte(currTime + " Hello World! \n")
data = Pack(data)
conn.Write(data)
}
}
func Pack(msg []byte) []byte {
var t uint8
var l uint16
if time.CurrentMilliSecond()%2 == 0 {
t = 66
} else {
t = 88
}
l = uint16(len(msg))
dataBuff := bytes.NewBuffer([]byte{})
if err := binary.Write(dataBuff, binary.BigEndian, t); err != nil {
return nil
}
if err := binary.Write(dataBuff, binary.BigEndian, l); err != nil {
return nil
}
if err := binary.Write(dataBuff, binary.BigEndian, msg); err != nil {
return nil
}
return dataBuff.Bytes()
}