美文网首页
tcp 粘包的问题

tcp 粘包的问题

作者: myonlyzzy | 来源:发表于2018-10-11 18:14 被阅读0次

tcp服务是一个流数据的双工服务,tcp client 端会源源不断的把二进制字节流发发给服务端.假设有下面一个这样的需求,我们需要发送一个用户信息给服务端.我们怎么样知道到那里是一个客户端发来的一个完整的用户信息呢,如果我们不认真处理这个问题就会产生粘包的问题,对于这个问题一般会有下面几种方式来解决.

  • 使用分格符
    如果我们约定一个分隔符作为我们2个用户数据之间的分隔,如果读到这个符号我们就约定一个完整的数据结构读完了.
  • 给数据头部添加数据部分长度,先读取长度,再根据这个长度数据剩下的数据.

定义协议

type Packet struct {
    Version   [2]byte
    Length    int16
    Timestamp int64
    Message   []byte
}

在这个协议中我们使用前2个字节表示协议版本,2个字节表示数据长度,8个字节表示时间戳,前12字节是属于协议头部部分,剩下的是数据部分.

server端

package main

import (
    "net"
    "log"
    "fmt"
    "encoding/binary"
    "time"

)

const (
    ProtocolVersion = "V1"
)

func main() {

    l, err := net.Listen("tcp", ":8090")
    if err != nil {
        log.Println(err)
    }
    defer l.Close()
    for {
        conn, err := l.Accept()
        if err != nil {
            log.Println(err)
        }
        go handlerConn(conn)
    }

}

func handlerConn(conn net.Conn) {
    defer conn.Close()
    header := make([]byte, 12)
    //var u user.User
    for {
        //read packet header
        _, err := conn.Read(header)
        if err != nil {
            return
        }
        if fmt.Sprintf("%s", header[:2]) != ProtocolVersion {
            log.Println("valid protoc version")
            return
        }
        timestamp := binary.BigEndian.Uint64(header[2:10])
        t := time.Unix(int64(timestamp), 0).Format("2006-01-02 03:04:05 PM")
        log.Printf("client send data time %s", t)
        length := int16(binary.BigEndian.Uint16(header[10:]))
        log.Println("data length", length)
        //read data
        databuf := make([]byte, length)
        _, err = conn.Read(databuf)
        if err != nil {
            return
        }
        fmt.Printf("%s\n", databuf)
        conn.Write(databuf)
    }

}

在server端先读取12个字节,然后分别读取出版本号和时间戳,数据长度.然后读取数据.

client 端

package main

import (
    "net"

    "log"
    "time"
    "math/rand"
    "encoding/binary"
    "github.com/myonlyzzy/go-exmaple/example5/pkg/user"
    "encoding/json"
)
type User struct {
    Name string `json:"name"`
    Age  int64  `json:"age"`
    Msg  string `json:"msg"`
}

func main() {
    addr := ":8090"
    conn, err := net.Dial("tcp", addr)
    if err != nil {
        log.Println(err)
    }
    for {
        msg := getRandString()
        u := user.User{
            Name: "john",
            Age:  24,
            Msg:  msg,
        }
        data, err := json.Marshal(u)
        if err != nil {
            log.Fatal(err)
        }
        dataLen := len(data)
        b := make([]byte, dataLen+12)
        b[0] = 'V'
        b[1] = '1'
        binary.BigEndian.PutUint64(b[2:10], uint64(time.Now().Unix()))
        binary.BigEndian.PutUint16(b[10:12], uint16(dataLen))
        copy(b[12:], data)
        _, err = conn.Write(b)
        if err != nil {
            log.Fatal(err)
        }
        time.Sleep(time.Second)
    }

}

func getRandString() string {
    length := rand.Intn(5000)
    strBytes := make([]byte, length)
    for i := 0; i < length; i++ {
        strBytes[i] = byte(rand.Intn(26) + 97)
    }
    return string(strBytes)
}

client端先将表示用户数据的json转成字节流然后取的长度,然后再分别填入头部信息。

总结

这是一个最简单的tcp数据包的结构定义,但基本原理就是这样。

相关文章

  • TCP粘包处理

    TCP粘包 TCP粘包的处理

  • JAVA-每日一面 2022-01-25

    什么是 TCP 粘包/拆包以及TCP 粘包/拆包的解决办法 TCP 粘包/拆包1、要发送的数据大于 TCP 发送缓...

  • golang 解决 TCP 粘包问题

    什么是 TCP 粘包问题以及为什么会产生 TCP 粘包,本文不加讨论。本文使用 golang 的 bufio.Sc...

  • tcp 粘包的问题

    tcp服务是一个流数据的双工服务,tcp client 端会源源不断的把二进制字节流发发给服务端.假设有下面一个这...

  • 消息粘包 和 消息不完整 问题

    消息粘包 和 消息不完整 问题 消息粘包 和 消息不完整问题 其实都是应用层会带来的问题,和TCP 没关系,TCP...

  • Socket粘包处理

    什么是粘包 TCP有粘包现象,而UDP不会出现粘包。 TCP(Transport Control Protocol...

  • TCP粘包

    什么是TCP粘包问题 多个TCP包粘在一个成为一个包,服务端处理接收的TCP包时,需要考虑拆包问题。 产生原因 发...

  • day32-粘包问题和报头的定制

    粘包问题 TCP协议作为流式协议,只有TCP协议存在粘包问题。 发送端可以是一K一K地发送数据,而接收端的应用程序...

  • TCP协议下的粘包与拆包,如何解决

    TCP协议下的粘包与拆包,如何解决 TCP协议下的粘包与拆包,如何解决一、粘包、拆包1.1 粘包原因1.1.1 滑...

  • netty的编解码

    什么是拆包/粘包 TCP 粘包/拆包 半包:读取的数据不是一个数据包粘包:读取的数据超过一个数据包 粘包问题的解决...

网友评论

      本文标题:tcp 粘包的问题

      本文链接:https://www.haomeiwen.com/subject/kvxiaftx.html