基于TCP服务的TLV编解码

基于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()
}
相关推荐
日更嵌入式的打工仔5 小时前
EtherCAT 逐帧解析状态机切换过程(初始清零阶段)
网络·信息与通信·ethercat
Danileaf_Guo6 小时前
256台H100服务器的RoCEv2无损与全互联算力网络建设方案
运维·服务器·网络
解压专家6666 小时前
怎么找书?怎么传输?在Kred里完成的全过程
运维·服务器·网络
两个人的幸福online6 小时前
cocos 使用 WebSocket(goEasy版)
网络·websocket·网络协议
NetInside_8 小时前
2025 DEM 趋势 × NetInside 产品能力:行业深度解读
运维·网络
usrcnusrcn8 小时前
智能建筑的 “隐形神经”:交换机如何连接安防、照明与门禁系统?
运维·服务器·网络
喵了meme8 小时前
C语言实战2
c语言·开发语言·网络
独行soc9 小时前
2025年渗透测试面试题总结-280(题目+回答)
网络·python·安全·web安全·网络安全·渗透测试·安全狮
唯创知音9 小时前
WT2605A录音方案实现高保真音频采集本地存储云端同步!
网络·音视频·录音芯片·录音方案·录音上传
@CLoudbays_Martin119 小时前
什么是IP黑洞?
网络·网络协议·tcp/ip