基于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()
}
相关推荐
一只小鱼儿吖24 分钟前
进程代理单窗口单IP技术:原理、应用与实现
网络·网络协议·tcp/ip
稳联技术26 分钟前
Ethernet IP与Profinet共舞:网关驱动绿色工业的智慧脉动
网络·网络协议·tcp/ip
学习3人组34 分钟前
CentOS配置网络
linux·网络·centos
计算机毕设定制辅导-无忧学长1 小时前
西门子 PLC 与 Modbus 集成:S7-1500 RTU/TCP 配置指南(一)
服务器·数据库·tcp/ip
高兴达1 小时前
RPC框架--实现一个非常简单的RPC调用
网络协议·rpc·firefox
~山有木兮2 小时前
LiteHub中间件之限流实现
网络·http·中间件
cui_win2 小时前
【网络】Linux 内核优化实战 - net.core.flow_limit_table_len
linux·运维·网络
BD_Marathon3 小时前
虚拟机网络检查
网络
游戏开发爱好者83 小时前
iOS App首次启动请求异常调试:一次冷启动链路抓包与初始化流程修复
websocket·网络协议·tcp/ip·http·网络安全·https·udp
2501_915106323 小时前
频繁迭代下完成iOS App应用上架App Store:一次快速交付项目的完整回顾
websocket·网络协议·tcp/ip·http·网络安全·https·udp