去语言怎么手动处理TCP粘包

  介绍

小编给大家分享一下走语言怎么手动处理TCP粘包,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获、下面让我们一起去了解一下吧!

<强>前言

一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消息数据,所以就会引发一次接收的数据无法满足消息的需要,导致粘包的存在。处理粘包的唯一方法就是制定应用层的数据通讯协议,通过协议来规范现有接收的数据是否满足消息数据的需要。在应用中处理粘包的基础方法主要有两种分别是以4节字描述消息大小或以结束符,实际上也有两者相结合的如HTTP、复述的通讯协议等。

<强>应用场景

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

坝镅栽趺词侄鞹CP粘包"

<强>粘包处理原理:通过请求头中数据包大小,将客户端N次发送的数据缓冲到一个数据包中

例如:

请求头占3个字节(指令头1字节,数据包长度2字节),版本占1个字节,指令占2个字节

协议规定一个数据包最大是512字节,请求头中数据包记录是1300字节,完整的数据包是1307个字节,此时服务器端需要将客户端3次发送数据进行粘包处理

<强>代码示例

package 服务器   import  (   ,“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(康涅狄格州,10240)   ,writer :=, bufio.NewWriter(康涅狄格州)   ,c :=,,客户{康涅狄格州:康涅狄格州,读者:读者,作者:作家}   return  c   }/* *   ,数据读取(粘包处理)   ,*/func (却;能够*客户)阅读(),{   ,for  {   var 才能;data []字节   var 才能;err 错误//读才能取指令头,返回输入流的前4个字节,不会移动读取位置   数据,才能,err =, this.reader.Peek (4)   if 才能len(数据),==,0,| |,err  !=, nil  {   ,才能继续   ,,}//才能返回缓冲中现有的可读取的字节数   var 才能;byteSize =, this.reader.Buffered ()   fmt.Printf才能(“读取字节长度:% d \ n",, byteSize)//生才能成一个字节数组,大小为缓冲中可读字节数   data =,才能使([]字节,,byteSize)//读才能取缓冲中的数据   this.reader.Read才能(数据)   fmt.Printf才能(“读取字节:% d \ n",,数据)//保才能存到新的缓冲区   for 才能,_,v :=, range  data  {   ,,this.Data =,附加(this.Data, v)   ,,}   if 才能len (this.Data), & lt;, 4, {   ,,//数据包缓冲区清空   ,,this.Data =,[]字节{}   ,,fmt.Printf(“非法数据,无指令头…\ n")   ,才能继续   ,,}   数据,才能,err =, protocol.HexBytesToBytes (this.Data [4])   instructHead,才能,_ :=, strconv.ParseUint(字符串(数据),16日,16)//指才能令头效验   if 才能uint16 (instructHead), !=, 42330, {   ,,fmt.Printf(“非法数据\ n")   ,,//数据包缓冲区清空   ,,this.Data =,[]字节{}   ,才能继续   ,,}   时间=data 才能;this.Data [: protocol.HEADER_SIZE]   var 才能;p =, protocol.Decode(数据)   fmt.Printf才能(“消息体长度:% d \ n",, p.Len)   var 才能;bodyLength =, len (this.Data),,   ,/* *   ,,判断数据包缓冲区的大小是否小于协议请求头中数据包大小   ,,如果小于,等待读取下一个客户端数据包,否则对数据包解码进行业务逻辑处理   ,,*/if 才能,int (p.Len),祝辞,len (this.Data),安康;protocol.HEADER_SIZE  {   ,,fmt.Printf(“身体体长度:% d,读取的身体体长度:% d \ n",, p.Len,, bodyLength)   ,才能继续   ,,}   fmt.Printf才能(“实际处理字节:% v \ n",, this.Data)   时间=p 才能;protocol.Decode (this.Data)//才能逻辑处理   go 才能this.logicHandler (p)//才能数据包缓冲区清空   时间=this.Data 才能;[]字节{}   ,}   }

去语言怎么手动处理TCP粘包