最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

GO語言如何手動處理TCP粘包詳解

 更新時間:2017年12月11日 13:51:11   作者:怪咖_OOP  
最近在用golang開發(fā)人工客服系統(tǒng)的時候碰到了粘包問題,那么什么是粘包呢?下面這篇文章就來給大家介紹了關于GO語言如何手動處理TCP粘包的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒。

前言

一般所謂的TCP粘包是在一次接收數(shù)據(jù)不能完全地體現(xiàn)一個完整的消息數(shù)據(jù)。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理數(shù)據(jù),再加上網(wǎng)絡上MTU的往往小于在應用處理的消息數(shù)據(jù),所以就會引發(fā)一次接收的數(shù)據(jù)無法滿足消息的需要,導致粘包的存在。處理粘包的唯一方法就是制定應用層的數(shù)據(jù)通訊協(xié)議,通過協(xié)議來規(guī)范現(xiàn)有接收的數(shù)據(jù)是否滿足消息數(shù)據(jù)的需要。在應用中處理粘包的基礎方法主要有兩種分別是以4節(jié)字描述消息大小或以結(jié)束符,實際上也有兩者相結(jié)合的如HTTP,redis的通訊協(xié)議等。

應用場景

大部分TCP通訊場景下,使用自定義通訊協(xié)議

粘包處理原理:通過請求頭中數(shù)據(jù)包大小,將客戶端N次發(fā)送的數(shù)據(jù)緩沖到一個數(shù)據(jù)包中

例如:

請求頭占3個字節(jié)(指令頭1字節(jié)、數(shù)據(jù)包長度2字節(jié)),版本占1個字節(jié),指令占2個字節(jié)

協(xié)議規(guī)定一個數(shù)據(jù)包最大是512字節(jié),請求頭中數(shù)據(jù)包記錄是1300字節(jié),完整的數(shù)據(jù)包是1307個字節(jié),此時服務器端需要將客戶端3次發(fā)送數(shù)據(jù)進行粘包處理

代碼示例

package server
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"
)
/*
 客戶端結(jié)構(gòu)體
 */
type Client struct {
 DeviceID string  //客戶端連接的唯標志
 Conn  net.Conn  //連接
 reader *bufio.Reader //讀取
 writer *bufio.Writer //輸出
 Data  []byte  //接收數(shù)據(jù)
}
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
}
/**
 數(shù)據(jù)讀?。ㄕ嘲幚恚?
 */
func (this *Client)read() {
 for {
  var data []byte
  var err error
  //讀取指令頭 返回輸入流的前4個字節(jié),不會移動讀取位置
  data, err = this.reader.Peek(4)
  if len(data) == 0 || err != nil {
   continue
  }
  //返回緩沖中現(xiàn)有的可讀取的字節(jié)數(shù)
  var byteSize = this.reader.Buffered()
  fmt.Printf("讀取字節(jié)長度:%d\n", byteSize)
  //生成一個字節(jié)數(shù)組,大小為緩沖中可讀字節(jié)數(shù)
  data = make([]byte, byteSize)
  //讀取緩沖中的數(shù)據(jù)
  this.reader.Read(data)
  fmt.Printf("讀取字節(jié):%d\n", data)
  //保存到新的緩沖區(qū)
  for _, v := range data {
   this.Data = append(this.Data, v)
  }
  if len(this.Data) < 4 {
   //數(shù)據(jù)包緩沖區(qū)清空
   this.Data = []byte{}
   fmt.Printf("非法數(shù)據(jù),無指令頭...\n")
   continue
  }
  data, err = protocol.HexBytesToBytes(this.Data[:4])
  instructHead, _ := strconv.ParseUint(string(data), 16, 16)
  //指令頭效驗
  if uint16(instructHead) != 42330 {
   fmt.Printf("非法數(shù)據(jù)\n")
   //數(shù)據(jù)包緩沖區(qū)清空
   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)  
  /**
   判斷數(shù)據(jù)包緩沖區(qū)的大小是否小于協(xié)議請求頭中數(shù)據(jù)包大小
   如果小于,等待讀取下一個客戶端數(shù)據(jù)包,否則對數(shù)據(jù)包解碼進行業(yè)務邏輯處理
   */
  if int(p.Len) > len(this.Data) - protocol.HEADER_SIZE {
   fmt.Printf("body體長度:%d,讀取的body體長度:%d\n", p.Len, bodyLength)
   continue
  }
  fmt.Printf("實際處理字節(jié):%v\n", this.Data)
  p = protocol.Decode(this.Data)
  //邏輯處理
  go this.logicHandler(p)
  //數(shù)據(jù)包緩沖區(qū)清空
  this.Data = []byte{}
 }
}

待優(yōu)化部分:

type Client struct {
 DeviceID string  //客戶端連接的唯標志
 Conn  net.Conn  //連接
 reader *bufio.Reader //讀取
 writer *bufio.Writer //輸出
 Data  []byte  //接收數(shù)據(jù)
}

結(jié)構(gòu)體中Data屬性可考慮使用bytes.Buffer實現(xiàn)。

Golang標準庫文檔:https://studygolang.com/pkgdoc

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • 下載golang.org/x包的操作方法

    下載golang.org/x包的操作方法

    今天小編就為大家分享一篇下載golang.org/x包的操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • Go語言設置JSON的默認值操作

    Go語言設置JSON的默認值操作

    這篇文章主要介紹了Go語言設置JSON的默認值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • GO語言映射(Map)用法分析

    GO語言映射(Map)用法分析

    這篇文章主要介紹了GO語言映射(Map)用法,以實例形式較為詳細的分析了針對映射的創(chuàng)建、填充、遍歷及修改等操作的技巧,需要的朋友可以參考下
    2014-12-12
  • Go基礎教程系列之defer、panic和recover詳解

    Go基礎教程系列之defer、panic和recover詳解

    這篇文章主要介紹了Go基礎教程系列之defer、panic和recover,需要的朋友可以參考下
    2022-04-04
  • Go Grpc Gateway兼容HTTP協(xié)議文檔自動生成網(wǎng)關

    Go Grpc Gateway兼容HTTP協(xié)議文檔自動生成網(wǎng)關

    這篇文章主要為大家介紹了Go Grpc Gateway兼容HTTP協(xié)議文檔自動生成網(wǎng)關示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Golang?Gin框架獲取請求參數(shù)的幾種常見方式

    Golang?Gin框架獲取請求參數(shù)的幾種常見方式

    在我們平常添加路由處理函數(shù)之后,就可以在路由處理函數(shù)中編寫業(yè)務處理代碼了,但在此之前我們往往需要獲取請求參數(shù),本文就詳細的講解下gin獲取請求參數(shù)常見的幾種方式,需要的朋友可以參考下
    2024-02-02
  • Go語言輸出函數(shù)使用詳解

    Go語言輸出函數(shù)使用詳解

    這篇文章主要介紹了Go語言輸出函數(shù)使用詳解的相關資料,需要的朋友可以參考下
    2023-08-08
  • Go語言內(nèi)建函數(shù)cap的實現(xiàn)示例

    Go語言內(nèi)建函數(shù)cap的實現(xiàn)示例

    cap 是一個常用的內(nèi)建函數(shù),它用于獲取某些數(shù)據(jù)結(jié)構(gòu)的容量,本文主要介紹了Go語言內(nèi)建函數(shù)cap的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • Go開源項目分布式唯一ID生成系統(tǒng)

    Go開源項目分布式唯一ID生成系統(tǒng)

    這篇文章主要為大家介紹了Go開源項目分布式唯一ID生成系統(tǒng)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Go??import _ 下劃線使用

    Go??import _ 下劃線使用

    這篇文章主要為大家介紹了Go??import下劃線_使用小技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12

最新評論

广水市| 布尔津县| 慈利县| 普陀区| 边坝县| 肇东市| 海丰县| 延安市| 河间市| 方正县| 分宜县| 英山县| 陆河县| 留坝县| 南宁市| 洪雅县| 广宁县| 县级市| 习水县| 资中县| 项城市| 胶南市| 峡江县| 台南县| 泾阳县| 昭觉县| 韶关市| 上饶市| 南宫市| 华蓥市| 正蓝旗| 利川市| 长阳| 百色市| 宿州市| 中阳县| 长沙县| 涿鹿县| 乡城县| 克拉玛依市| 山东省|