基于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()
}
相关推荐
pemper_1 小时前
怎么操作使http变成https访问?
网络·网络协议·http·https·ssl
蒙奇·D·路飞-1 小时前
古诗词四首鉴赏
网络
Run_Snails2 小时前
hcia-openEuler V1.0师资题库-试卷3
运维·服务器·网络
学java的小菜鸟啊2 小时前
第五章 网络编程 TCP/UDP/Socket
java·开发语言·网络·数据结构·网络协议·tcp/ip·udp
新手嵌入式学习3 小时前
网络协议头分析
网络·网络协议
运维Z叔4 小时前
云安全 | AWS S3存储桶安全设计缺陷分析
android·网络·网络协议·tcp/ip·安全·云计算·aws
weixin_456732595 小时前
网络-内核是如何与用户进程交互
网络·交互
陈大爷(有低保)5 小时前
UDP Socket聊天室(Java)
java·网络协议·udp
爱吃涮毛肚的肥肥(暂时吃不了版)5 小时前
计算机网络34——Windows内存管理
网络·计算机网络·udp
码哝小鱼6 小时前
firewalld封禁IP或IP段
linux·网络