golang网络socket粘包问题的解决方法
本文实例讲述了golang网络socket粘包问题的解决方法。分享给大家供大家参考,具体如下:
看到很多人问这个问题,今天就写了个例子,希望能帮助大家
首先说一下什么是粘包:百度上比较通俗的说法是指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
解决方案如下:
服务端:
packagemain
import(
"bytes"
"encoding/binary"
"fmt"
"io"
"net"
)
funcmain(){
//监听端口
ln,err:=net.Listen("tcp",":6000")
iferr!=nil{
fmt.Printf("ListenError:%s\n",err)
return
}
//监听循环
for{
//接受客户端链接
conn,err:=ln.Accept()
iferr!=nil{
fmt.Printf("AcceptError:%s\n",err)
continue
}
//处理客户端链接
gohandleConnection(conn)
}
}
funchandleConnection(connnet.Conn){
//关闭链接
deferconn.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)
iferr==io.EOF{
fmt.Printf("Clientexit:%s\n",conn.RemoteAddr())
}
iferr!=nil{
fmt.Printf("Readerror:%s\n",err)
return
}
fmt.Println(databuf[:n])
//数据添加到消息缓冲
n,err=msgbuf.Write(databuf[:n])
iferr!=nil{
fmt.Printf("Bufferwriteerror:%s\n",err)
return
}
//消息分割循环
for{
//消息头
iflength==0&&msgbuf.Len()>=4{
binary.Read(msgbuf,binary.LittleEndian,&ulength)
length=int(ulength)
//检查超长消息
iflength>10240{
fmt.Printf("Messagetoolength:%d\n",length)
return
}
}
//消息体
iflength>0&&msgbuf.Len()>=length{
fmt.Printf("Clientmessge:%s\n",string(msgbuf.Next(length)))
length=0
}else{
break
}
}
}
}
客户端:
packagemain
import(
"bytes"
"encoding/binary"
"fmt"
"net"
"time"
)
funcmain(){
//链接服务器
conn,err:=net.Dial("tcp","127.0.0.1:6000")
iferr!=nil{
fmt.Printf("Dialerror:%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条消息
fori:=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语言程序设计有所帮助。