我们想要获取完整的报文,首先得知道消息的长度和起始位置然后来读取。通常有以下几种方法。
- 使用带消息头的协议,头部写入包长度,然后再读取包内容。
- 设置定长消息,每次读取定长内容,长度不够时空位补固定字符。
- 设置消息边界,服务端从网络流中按消息边界分离出消息内容,—般使用‘\n’。
- 更为复杂的协议,例如json、protobuf。
今天用go来实现一个简洁的带消息头的tcp传输方式。传输格式:消息头(自己定义)+ 正文长度 + 正文。
我们专门写一个包用于socket传输时消息的编码和解码。
MsgHeader = “1a2b3c4d” (自己定义)
首先编码的时候,我们希望将上面对应的传输格式写入socket。
func Encoder(buffer io.Writer,content string) error{
err := binary.Write(buffer,binary.BigEndian,[]byte(MsgHeader))
if err != nil{
return err
}
clen := int32(len([]byte(content)))
err = binary.Write(buffer,binary.BigEndian,clen)
if err != nil{
return err
}
err = binary.Write(buffer,binary.BigEndian,[]byte(content))
if err != nil{
return err
}
return nil
}
解码就很简单,首先取出头部(我们自己知道头部的长度)然后和自己定义的头部进行比对,若相同再取出正文长度,然后通过正文长度取出完整的正文。
func Decoder(reader io.Reader)(res []byte,err error){
hBuf := make([]byte,len(MsgHeader))
if _,err = io.ReadFull(reader,hBuf);err != nil{
return nil,err
}
if string(hBuf) != MsgHeader{
return nil,errors.New("消息头部不一样")
}
lengthBuf := make([]byte,4)
if _,err = io.ReadFull(reader,lengthBuf);err != nil{
return nil,err
}
len := binary.BigEndian.Uint32(lengthBuf)
bodyBuf := make([]byte,len)
if _,err = io.ReadFull(reader,bodyBuf);err != nil{
return nil,err
}
return bodyBuf,nil
}
我们通过客户端和服务器来实现一下。
客户端通过拨号来访问服务器的端口,通过socket编码后进行访问。这里注意要记得关闭连接。
func main() {
conn, err := net.Dial("tcp", ":8080")
if err != nil{
panic(err)
}
defer conn.Close()
full_content.Encoder(conn,"hello there")
}
服务器端监听一个端口,然后得到socket,go一个协程出去处理socket,打印得到的正文。
package main
import (
"fmt"
"goTrip/net/full_content"
"net"
)
func main() {
listen, err := net.Listen("tcp", "localhost:8080")
if err != nil{
panic(err)
}
for{
accept, err := listen.Accept()
if err != nil{
panic(err)
}
go process(accept)
}
}
func process(conn net.Conn){
defer conn.close()
decoder, err := full_content.Decoder(conn)
if err != nil{
panic(err)
}
str := string(decoder)
fmt.Println("msg: ",str)
}
最后得到消息:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)