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语言程序设计有所帮助。