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

 更新时间:2016年07月22日 09:47:40   作者:dotcoo  
这篇文章主要介绍了golang网络socket粘包问题的解决方法,简单讲述了socket粘包的定义并结合实例形式分析了Go语言解决粘包问题的方法,需要的朋友可以参考下

本文实例讲述了golang网络socket粘包问题的解决方法。分享给大家供大家参考,具体如下:

看到很多人问这个问题, 今天就写了个例子, 希望能帮助大家

首先说一下什么是粘包:百度上比较通俗的说法是指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾

解决方案如下:

服务端:

复制代码 代码如下:
package main
import (
    "bytes"
    "encoding/binary"
    "fmt"
    "io"
    "net"
)
func main() {
    // 监听端口
    ln, err := net.Listen("tcp", ":6000")
    if err != nil {
        fmt.Printf("Listen Error: %s\n", err)
        return
    }
    // 监听循环
    for {
        // 接受客户端链接
        conn, err := ln.Accept()
        if err != nil {
            fmt.Printf("Accept Error: %s\n", err)
            continue
        }
        // 处理客户端链接
        go handleConnection(conn)
    }
}
func handleConnection(conn net.Conn) {
    // 关闭链接
    defer conn.Close()
    // 客户端
    fmt.Printf("Client: %s\n", conn.RemoteAddr())
    // 消息缓冲
    msgbuf := bytes.NewBuffer(make([]byte, 0, 10240))
    // 数据缓冲
    databuf := make([]byte, 4096)
    // 消息长度
    length := 0
    // 消息长度uint32
    ulength := uint32(0)
    // 数据循环
    for {
        // 读取数据
        n, err := conn.Read(databuf)
        if err == io.EOF {
            fmt.Printf("Client exit: %s\n", conn.RemoteAddr())
        }
        if err != nil {
            fmt.Printf("Read error: %s\n", err)
            return
        }
        fmt.Println(databuf[:n])
        // 数据添加到消息缓冲
        n, err = msgbuf.Write(databuf[:n])
        if err != nil {
            fmt.Printf("Buffer write error: %s\n", err)
            return
        }
        // 消息分割循环
        for {
            // 消息头
            if length == 0 && msgbuf.Len() >= 4 {
                binary.Read(msgbuf, binary.LittleEndian, &ulength)
                length = int(ulength)
                // 检查超长消息
                if length > 10240 {
                    fmt.Printf("Message too length: %d\n", length)
                    return
                }
            }
            // 消息体
            if length > 0 && msgbuf.Len() >= length {
                fmt.Printf("Client messge: %s\n", string(msgbuf.Next(length)))
                length = 0
            } else {
                break
            }
        }
    }
}

客户端:

复制代码 代码如下:
package main
import (
    "bytes"
    "encoding/binary"
    "fmt"
    "net"
    "time"
)
func main() {
    // 链接服务器
    conn, err := net.Dial("tcp", "127.0.0.1:6000")
    if err != nil {
        fmt.Printf("Dial error: %s\n", err)
        return
    }
    // 客户端信息
    fmt.Printf("Client: %s\n", conn.LocalAddr())
    // 消息缓冲
    msgbuf := bytes.NewBuffer(make([]byte, 0, 1024))
    // 消息内容
    message := []byte("我是utf-8的消息")
    // 消息长度
    messageLen := uint32(len(message))
    // 消息总长度
    mlen := 4 + len(message)
    // 写入5条消息
    for i := 0; i < 10; i++ {
        binary.Write(msgbuf, binary.LittleEndian, messageLen)
        msgbuf.Write(message)
    }
    // 单包发送一条消息
    conn.Write(msgbuf.Next(mlen))
    time.Sleep(time.Second)
    // 单包发送三条消息
    conn.Write(msgbuf.Next(mlen * 3))
    time.Sleep(time.Second)
    // 发送不完整的消息头
    conn.Write(msgbuf.Next(2))
    time.Sleep(time.Second)
    // 发送消息剩下部分
    conn.Write(msgbuf.Next(mlen - 2))
    time.Sleep(time.Second)
    // 发送不完整的消息体
    conn.Write(msgbuf.Next(mlen - 6))
    time.Sleep(time.Second)
    // 发送消息剩下部分
    conn.Write(msgbuf.Next(6))
    time.Sleep(time.Second)
    // 多段发送
    conn.Write(msgbuf.Next(mlen + 2))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-2 + mlen - 8))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(8 + 1))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-1 + mlen + mlen))
    time.Sleep(time.Second)
    // 关闭链接
    conn.Close()
}

希望本文所述对大家Go语言程序设计有所帮助。

相关文章

  • Golang Web 框架Iris安装部署

    Golang Web 框架Iris安装部署

    这篇文章主要为大家介绍了Golang Web 框架Iris安装部署,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 一文掌握Go语言并发编程必备的Mutex互斥锁

    一文掌握Go语言并发编程必备的Mutex互斥锁

    Go 语言提供了 sync 包,其中包括 Mutex 互斥锁、RWMutex 读写锁等同步机制,本篇博客将着重介绍 Mutex 互斥锁的基本原理,需要的可以参考一下
    2023-04-04
  • Go语言学习之条件语句使用详解

    Go语言学习之条件语句使用详解

    这篇文章主要介绍了Go语言中条件语句的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • go语言 xorm框架 postgresql 的用法及详细注解

    go语言 xorm框架 postgresql 的用法及详细注解

    这篇文章主要介绍了go语言 xorm框架 postgresql 的用法及详细注解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang监听ip数据包的实现步骤(golang纯享版)

    golang监听ip数据包的实现步骤(golang纯享版)

    这篇文章主要给大家介绍了golang监听ip数据包的实现步骤,本文以ip4 作为案例进行包抓取示范,ip6抓取与ip4方式异曲同工,可自行举一反三得出,文中通过图文结合给大家介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • 如何使用Goland IDE go mod 方式构建项目

    如何使用Goland IDE go mod 方式构建项目

    这篇文章主要介绍了如何使用Goland IDE go mod 方式构建项目,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • GO语言结构体面向对象操作示例

    GO语言结构体面向对象操作示例

    这篇文章主要介绍了GO语言编程中结构体面向对象的操作示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • go语言中函数与方法介绍

    go语言中函数与方法介绍

    这篇文章介绍了go语言中的函数与方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • go env环境变量配置的使用

    go env环境变量配置的使用

    在安装和使用Go时,必须要正确地配置环境变量,本文主要介绍了go env环境变量配置的使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • golang 解析word文档操作

    golang 解析word文档操作

    这篇文章主要介绍了golang 解析word文档操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论