博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GO语言手动处理TCP粘包
阅读量:6940 次
发布时间:2019-06-27

本文共 2310 字,大约阅读时间需要 7 分钟。

应用场景

大部分TCP通讯场景下,使用自定义通讯协议

粘包处理原理:通过请求头中数据包大小,将客户端N次发送的数据缓冲到一个数据包中 例如: 请求头占3个字节(指令头1字节、数据包长度2字节),版本占1个字节,指令占2个字节 协议规定一个数据包最大是512字节,请求头中数据包记录是1300字节,完整的数据包是1307个字节,此时服务器端需要将客户端3次发送数据进行粘包处理

代码示例

package serverimport (	"net"	"bufio"	"ftj-data-synchro/protocol"	"golang.org/x/text/transform"	"golang.org/x/text/encoding/simplifiedchinese"	"io/ioutil"	"bytes"	"ftj-data-synchro/logic"	"fmt"	"strconv")/* 客户端结构体 */type Client struct {	DeviceID string        //客户端连接的唯标志	Conn     net.Conn      //连接	reader   *bufio.Reader //读取	writer   *bufio.Writer //输出	Data     []byte        //接收数据}func NewClient(conn *net.TCPConn) *Client {	reader := bufio.NewReaderSize(conn, 10240)	writer := bufio.NewWriter(conn)	c := &Client{Conn:conn, reader:reader, writer:writer}	return c}/**	数据读取(粘包处理) */func (this *Client)read() {	for {		var data []byte		var err error		//读取指令头 返回输入流的前4个字节,不会移动读取位置		data, err = this.reader.Peek(4)		if len(data) == 0 || err != nil {			continue		}		//返回缓冲中现有的可读取的字节数		var byteSize = this.reader.Buffered()		fmt.Printf("读取字节长度:%d\n", byteSize)		//生成一个字节数组,大小为缓冲中可读字节数		data = make([]byte, byteSize)		//读取缓冲中的数据		this.reader.Read(data)		fmt.Printf("读取字节:%d\n", data)		//保存到新的缓冲区		for _, v := range data {			this.Data = append(this.Data, v)		}		if len(this.Data) < 4 {			//数据包缓冲区清空			this.Data = []byte{}			fmt.Printf("非法数据,无指令头...\n")			continue		}		data, err = protocol.HexBytesToBytes(this.Data[:4])		instructHead, _ := strconv.ParseUint(string(data), 16, 16)		//指令头效验		if uint16(instructHead) != 42330 {			fmt.Printf("非法数据\n")			//数据包缓冲区清空			this.Data = []byte{}			continue		}		data = this.Data[:protocol.HEADER_SIZE]		var p = protocol.Decode(data)		fmt.Printf("消息体长度:%d\n", p.Len)		var bodyLength = len(this.Data)		      /**			判断数据包缓冲区的大小是否小于协议请求头中数据包大小			如果小于,等待读取下一个客户端数据包,否则对数据包解码进行业务逻辑处理		 */		if int(p.Len) > len(this.Data) - protocol.HEADER_SIZE {			fmt.Printf("body体长度:%d,读取的body体长度:%d\n", p.Len, bodyLength)			continue		}		fmt.Printf("实际处理字节:%v\n", this.Data)		p = protocol.Decode(this.Data)		//逻辑处理		go this.logicHandler(p)		//数据包缓冲区清空		this.Data = []byte{}	}}复制代码

待优化部分:

type Client struct {    DeviceID string        //客户端连接的唯标志    Conn     net.Conn      //连接    reader   *bufio.Reader //读取    writer   *bufio.Writer //输出    Data     []byte        //接收数据}复制代码

结构体中Data属性可考虑使用bytes.Buffer实现。

转载地址:http://rwsnl.baihongyu.com/

你可能感兴趣的文章
嵌入式开发之C基础学习笔记10--总结
查看>>
我的友情链接
查看>>
linux
查看>>
Scala 入门学习
查看>>
Android开发之ListView开发中view对象的复用问题2
查看>>
HTMLTestRunner测试报告美化
查看>>
数据库----性能优化
查看>>
linux 系统 sar 命令详解
查看>>
QT开发(六十四)——QT样式表(三)
查看>>
LVM卷管理及配额设置
查看>>
嵌入式系统烧写uboot/bootloader/kernel的一般方法
查看>>
RHEL7 配置http虚拟主机
查看>>
Xshell连接Linux下Oracle无法回退的解决办法
查看>>
将字符串倒序输出
查看>>
Web开发:我希望得到的编程学习路线图(转)
查看>>
BZOJ3322[Scoi2013]摩托车交易——最大生成树+贪心+倍增
查看>>
Hive 读取的Column值为NULL?!
查看>>
Java基础学习总结(5)——多态
查看>>
BlackEnergy 针对思科路由器增加了新的***功能
查看>>
Ubuntu下MySQL5.7配置字符集utf8和sql_mode
查看>>