golang中解决tcp传输中的粘包问题

golang中解决tcp传输中的粘包问题

Author: 岳东卫
Email: usher.yue@gmail.com

什么是粘包?

最近在写https://github.com/UsherYue/ActivedRouter (一个http/https反向代理服务)的时候遇到了粘包问题,

如果有做过网络编程的小伙伴应该都知道粘包问题,举个例子: 比如客户端在和服

务器进行通信采用的是json格式的数据包。那么此时Client和Server的数据交互流程应该如下:

Client Send Json Data->经过网络->Server Reveive Data->Server Decode Json ->Done (一次交互只有一个Json数据包)

上述流程我们假设从客户端发送到服务器接收这个一次的性动作中间交互的数

据是一个完成的json数据包,因此我们的程序可以正常工作。

但是实际情况并不是我们想的这样,由于TCP协议的特点、以及网络环境的复杂

多变、以及服务器对客户端的数据接收处理不及时等等原因,会导致网络传输

过程中出现粘包。 也就是说在服务器进行一次数据读取的时候,我们假想这

个数据包是一个完整的json数据包,但是实际上他确实 ,2个Json 数据包、3

个json数据包、2.5个json数据包,这就是我们所说的粘包。
如果你还不能理解那么看下图。

我们如何解决粘包问题?

我们在开发过程中通常会在server端接收数据的时候定义一个固定长度的buffer来存储从客户端连接发来的数据包 ,然后对这个数据包进行反序列化,所以要解决这个问题我们就要从收发数据的时候做一些手脚, 思路如下:

Client Send Json Data->调用封装方法将数据封装成固定格式的Packet->经过网络->Server Reveive Data->调用解封装方法取出粘包packet中所有json数据包,并将剩余截断数据和下一次到来的数据包进行拼接->Server Decode Json ->Done (一次交互只有一个Json数据包)

我在golang中实现了一个Packet封装代码如下,可直接使用:

package packet

import (
    "bytes"
    "encoding/binary"
)

const (
    DEFAULE_HEADER           = "[**********]"
    DEFAULT_HEADER_LENGTH    = 12
    DEFAULT_SAVE_DATA_LENGTH = 4
)

type Packet struct {
    Header         string
    HeaderLengh    int32
    SaveDataLength int32
    Data           []byte
}

//set delimiter header
func (self *Packet) SetHeader(header string) *Packet {
    self.Header = header
    self.HeaderLengh = int32(len([]byte(header)))
    return self
}

//create default package
func NewDefaultPacket(data []byte) *Packet {
    return &Packet{DEFAULE_HEADER, DEFAULT_HEADER_LENGTH, DEFAULT_SAVE_DATA_LENGTH, data}
}

//convert to net package
func (self *Packet) Packet() []byte {
    return append(append([]byte(self.Header), self.IntToBytes(int32(len(self.Data)))...), self.Data...)
}

//return value is sticky data
func (self *Packet) UnPacket(readerChannel chan []byte) []byte {
    dataLen := int32(len(self.Data))
    var i int32
    for i = 0; i < dataLen; i++ {
        //Termiate for loop when the remaining data is insufficient .
        if dataLen < i+self.HeaderLengh+self.SaveDataLength {
            break
        }
        //find Header
        if string(self.Data[i:i+self.HeaderLengh]) == self.Header {
            saveDataLenBeginIndex := i + self.HeaderLengh
            actualDataLen := self.BytesToInt(self.Data[saveDataLenBeginIndex : saveDataLenBeginIndex+self.SaveDataLength])
            //The remaining data is less than one package
            if dataLen < i+self.HeaderLengh+self.SaveDataLength+actualDataLen {
                break
            }
            //Get a packet
            packageData := self.Data[saveDataLenBeginIndex+self.SaveDataLength : saveDataLenBeginIndex+self.SaveDataLength+actualDataLen]
            //send pacakge data to reader channel
            readerChannel <- packageData
            //get next package index
            i += self.HeaderLengh + self.SaveDataLength + actualDataLen - 1
        }
    }
    //Reach the end
    if i >= dataLen {
        return []byte{}
    }
    //Returns the remaining data
    return self.Data[i:]
}

func (self *Packet) IntToBytes(i int32) []byte {
    byteBuffer := bytes.NewBuffer([]byte{})
    binary.Write(byteBuffer, binary.BigEndian, i)
    return byteBuffer.Bytes()
}

func (self *Packet) BytesToInt(data []byte) int32 {
    var val int32
    byteBuffer := bytes.NewBuffer(data)
    binary.Read(byteBuffer, binary.BigEndian, &val)
    return val
}

Client实现伪代码代码如下:

  dataPackage := NewDefaultPacket([]byte(jsonString)).Packet()
  Client.Write(dataPackage)

Server实现伪代码代码如下:

  //Declare a pipe for receiving unpacked data
    readerChannel := make(chan []byte, 1024)
    //Store truncated data
    remainBuffer := make([]byte, 0)
    //read unpackage data from buffered channel
    go func(reader chan []byte) {
        for {
            packageData := <-reader
            //....balabala....
        }
    }(readerChannel)
  remainBuffer =   NewDefaultPacket(append(remainBuffer,recvData)).UnPacket(readerChannel)
时间: 2024-11-10 10:21:56

golang中解决tcp传输中的粘包问题的相关文章

(经典)tcp粘包分析

这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下:  一 .两个简单概念长连接与短连接:1.长连接     Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收. 2.短连接     Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接.此种方式常用于一点对多点 通讯,比如多个Client连接一个Server.  二 .什么时候需要考虑粘包问题? 1:如

解决TCP网络传输“粘包”问题

当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport control protocol,传输控制协议)是面向连接的,提供高可靠性服务.UDP(user datagram protocol,用户数据报协议)是无连接的,提供高效率服务.在实际工程应用中,对可靠性和效率的选择取决于应用的环境和需求.一般情况下,普通数据的网络传输采用高效率的udp,重要数据的网络传输采用

解决TCP网络传输“粘包”问题,互联网营销

当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport control protocol,传输控制协议)是面向连接的,提供高可靠性服务.UDP(user datagram protocol,用户数据报协议)是无连接的,提供高效率服务.在实际工程应用中,对可靠性和效率的选择取决于应用的环境和需求.一般情况下,普通数据的网络传输采用高效率的udp,重要数据的网络传输采用

Android中实现TCP和UDP传输实例_Android

TCP和UDP在网络传输中非常重要,在Android开发中同样重要. 首先我们来看一下什么是TCP和UDP. 什么是TCP? TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的.可靠的.基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified).在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能.应用层向TCP层发送用于网间传输的.用8位字节表示的数据流,然后TCP

golang网络socket粘包问题的解决方法_Golang

本文实例讲述了golang网络socket粘包问题的解决方法.分享给大家供大家参考,具体如下: 看到很多人问这个问题, 今天就写了个例子, 希望能帮助大家 首先说一下什么是粘包:百度上比较通俗的说法是指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾. 解决方案如下: 服务端: 复制代码 代码如下: package main import (     "bytes"     "encoding/binary&quo

处理TCP网络传输“粘包”疑难

在应用开发过程中,笔者发现基于TCP网络传输的应用程序有时会出现粘包现象(即发送方发送的若干包数据到接收方接收时粘成一包).针对这种情况,我们进行了专题研究与实验.本文重点分析了TCP网络粘包问题,并结合实验结果提出了解决该问题的对策和方法,供有关工程技术人员参考. 一.TCP协议简介 TCP是一个面向连接的传输层协议,虽然TCP不属于iso制定的协议集,但由于其在商业界和工业界的成功应用,它已成为事实上的网络标准,广泛应用于各种网络主机间的通信. 作为一个面向连接的传输层协议,TCP的目标是为

[摘]在linux内核中修改TCP MSS值

http://blog.csdn.net/force_eagle/article/details/4592271http://www.netfilter.org/documentation/HOWTO/netfilter-extensions-HOWTO-4.html http://lartc.org/howto/lartc.cookbook.mtu-mss.html As explained above, Path MTU Discovery doesn't work as well as i

现代企业IT系统中的文件传输浅析

问题描述 随着信息化程度的加深,现代企业的数据化程度也越来越高,各种财务数据.设计图纸.制造BOM.库存.采购.销售等数据信息,它们的存在形式也往往是各种不同类型的文件,如.doc,.xls,.ppt,.pdf等,逐步成为企业重要数字资产.但这些数据往往不是静止的,它们具有相当的时效性和流动性,只有在规定时间内,在特定的系统中,经过整理.归纳.统计.分析,才会实现数据的价值.因此除了对于企业内部的OA.ERP.BI.CRM等IT系统的建设以外,现代企业对于跨地域.跨系统间的文件传输,也正成为IT

Socket编程 (异步通讯,解决Tcp粘包) - Part3

原文 http://www.cnblogs.com/zengqinglei/archive/2013/05/14/3078842.html Socket编程 (异步通讯,解决Tcp粘包) 从上一章的通讯中,我们发现如果使用Tcp连续发送消息会出现消息一起发送过来的情况,这样给我们编程造成一定的问题,给我们的信息解析造成一定的问题.那么这篇文章就将针对以上问题给出解决方案......   问题一般会出现的情况如下,假设我们连续发送两条两天记录("我是liger_zql"): 模拟发送示例