Golang TCP粘包拆包问题的解决方法

  


  

  

最近在使用Golang编写套接字层,发现有时候接收端会一次读到多个数据包的问题。于是通过查阅资料,发现这个就是传说中TCP的粘包问题。下面通过编写代码来重现这个问题:
  

  

服务端代码服务器/主要。去
  

        函数main () {   l,犯错:=净。听(“tcp”、“: 4044”)   如果犯错!=nil {   恐慌(err)   }   fmt。Println(“听4044”)   为{//监听到新的连接,创建新的goroutine交给handleConn函数处理   康涅狄格州,犯错:=l.Accept ()   如果犯错!=nil {   fmt。Println(“康涅狄格州犯错:“犯错)   其他}{   去handleConn(康涅狄格州)   }   }   }      func handleConn(康涅狄格州net.Conn) {   推迟conn.Close ()   推迟fmt.Println(“关闭”)   fmt。Println(“新连接:“,conn.RemoteAddr ())      结果:=bytes.NewBuffer(零)   var buf[1024]字节   为{   n,犯错:=conn.Read (buf [0:])   result.Write (buf (0: n))   如果犯错!=nil {   如果做错了==OF {   继续   其他}{   fmt。Println(“读错:“犯错)   打破   }   其他}{   fmt。Println (“recv:“, result.String ())   }   result.Reset ()   }   }      


  

        函数main () {   数据:=[]字节(“这里才是一个完整的数据包]”)   康涅狄格州,犯错:=净。DialTimeout (“tcp”、“localhost: 4044”, time.Second * 30)   如果犯错!=nil {   fmt。Printf(“连接失败,犯错:% v \ n”, err.Error ())   返回   }   我:=0;我& lt; 1000;我+ + {   _,呃=conn.Write(数据)   如果犯错!=nil {   fmt。Printf("写失败,错误:% v \ n”,呃)   打破   }   }   }      

<>强运行结果
  

  
  4044年


  新连接:[::1]:53079
  recv:[这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据& # 65533;
  recv: & # 65533;][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包]
  recv:[这里才是一个完整的数据包]
  recv:[这里才是一个完整的数据包]
  recv:[这里才是一个完整的数据包][这里才是一个完整的数据包][这里才是一个完整的数据包]
  recv:[这里才是一个完整的数据包]
  …省略其它的…
  

     

从服务端的控制台输出可以看的出,存在三种类型的输出:

  
      <李>一种是正常的一个数据包输出。   <李>一种是多个数据包“粘”在了一起,我们定义这种读到的包为粘包。   <李>一种是一个数据包被“拆”开,形成一个破碎的包,我们定义这种包为半包。   
  

<强>为什么会出现半包和粘包吗?

  
      <李>客户端一段时间内发送包的速度太多,服务端没有全部处理完。于是数据就会积压起来,产生粘包。   <李>定义的读的缓冲区不够大,而数据包太大或者由于粘包产生,服务端不能一次全部读完,产生半包。   
  

<强>什么时候需要考虑处理半包和粘包吗?

  

TCP连接是长连接,即一次连接多次发送数据。
  每次发送的数据是结构的,比如JSON格式的数据或者数据包的协议是由我们自己定义的(包头部包含实际数据长度,协议魔数等)。

  

<>强解决思路

  
      <李>定长分隔(每个数据包最大为该长度,不足时使用特殊字符填充),但是数据不足时会浪费传输资源李

    Golang TCP粘包拆包问题的解决方法