基于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()
}
相关推荐
千天夜32 分钟前
使用UDP协议传输视频流!(分片、缓存)
python·网络协议·udp·视频流
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
xianwu5431 小时前
反向代理模块
linux·开发语言·网络·git
follycat1 小时前
[极客大挑战 2019]HTTP 1
网络·网络协议·http·网络安全
earthzhang20212 小时前
《深入浅出HTTPS》读书笔记(5):随机数
网络协议·http·https
xiaoxiongip6662 小时前
HTTP 和 HTTPS
网络·爬虫·网络协议·tcp/ip·http·https·ip
JaneJiazhao2 小时前
HTTPSOK:SSL/TLS证书自动续期工具
服务器·网络协议·ssl
JaneJiazhao2 小时前
HTTPSOK:智能SSL证书管理的新选择
网络·网络协议·ssl
CXDNW2 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
无所谓จุ๊บ3 小时前
树莓派开发相关知识十 -小试服务器
服务器·网络·树莓派