标签:std protocol 命令 拆分 nil UNC cep else listener
0,server服务端——常规版本
package main //server服务端 import ( "fmt" "net" ) func main() { //01,启动服务 net.Listen listener, err1 := net.Listen("tcp", "127.0.0.1:20000") //net.Listen网络.监听 if err1 != nil { fmt.Println("12.0.0.1:20000 连接错误!!!") return } //02,监听.接收连接 listener.Accept(),用 for循环建立多个请求 for { conn, err2 := listener.Accept() //listener.Accept收听.接收 if err2 != nil { fmt.Println("accept 接受请求错误!!!") return } //03,读取信息 连接对象.Read([]byte存放信息),发送客户端 go conn_(conn) } } //--------------------------使用函数------------------------------ func conn_(conn net.Conn) { var tmp [128]byte for { n, err := conn.Read(tmp[:]) //用for 循环 conn对象可以一直保持接收 if err != nil { fmt.Println("客户端读取错误!!!!") return } fmt.Println(string(tmp[:n])) } }
1,client客户端——常规版本
package main //client客户端 import ( "fmt" "net" //"bufio" //"os" //"strings" ) func main() { //01,与server端建立连接 conn, err1 := net.Dial("tcp", "127.0.0.1:20000") //net.Dial网络.拨号 if err1 != nil { fmt.Println("dial 127.0.0.1:20000 failed,err") return } //02,发送数据 //var msg string /*用法1 用命令行参数os.Args发出 if len(os.Args) < 2 { msg = "hello wangye!!!" } else { msg = os.Args[1] } conn.Write([]byte(msg)) */ /*用法2 循环发出 input 用户数据 > 弊端无法过滤空格输出 for { fmt.Print("请老大发言:") fmt.Scanln(&msg) if msg == "exit" { break } conn.Write([]byte(msg)) }*/ /*用法3 用bufio.NewReader() for { reader := bufio.NewReader(os.Stdin) //从标准输入生成读对象 fmt.Print("请老大发言:") text, _ := reader.ReadString(‘\n‘) //读到换行 text = strings.TrimSpace(text) //trim space去除空格 conn.Write([]byte(text)) }*/ for i := 0; i < 20; i++ { msg := "黑鲁,黑鲁,how are you?" b, err := proto.Encode(msg) if err != nil { fmt.Println("Encode failed,err:", err) } conn.Write(b) } //03,关闭程序 defer conn.Close() } //--------------------------使用函数------------------------------
上面 for 循环发送消息,速度快,存在粘包
//出现"粘包"的关键在于接收方不确定数据包大小,可以将数据封包和拆包。
//封包: 封包就是给一段数据加包头,过滤非法包时封包会加入”包尾“内容
//包头长度固定,且储存包体长度,根据包头长度固定和包体长度的变量就能确定拆分出完整数据包
//自己定义一个协议,比如数据包前4个字节为包头,储存的是发送的数据长度
自写一个protocol包,调用里面的 Encode()编码, DEcode()解码
0,粘包方案
package proto import ( "bufio" "bytes" "encoding/binary" //编码/二进制 ) //01,先用 binary.Write() 将消息打包成 int32 4个字节,小端排列对象 //02,再用 binary.Read() 将消息按照4字节,小端读取(1次读标准长度来避免粘包) //Encode 将消息编码 func Encode(message string) ([]byte, error) { //读取长度,转换成int32类型(占4个字节) length := int32(len(message)) //定义一个字节类型的缓冲对象,具有Read 和Write 方法的包 pkg := new(bytes.Buffer) //调用二进制写入函数,把pck包对象,按照传入int32类型的长度,小端方式排列 err := binary.Write(pkg, binary.LittleEndian, length) if err != nil { //如果对象不为空,返回空,和对象 return nil, err } //小端方式写入类容 err = binary.Write(pkg, binary.LittleEndian, []byte(message)) if err != nil { return nil, err } //把Bytes.Buffer对象 转换成Bytes()对象返回 return pkg.Bytes(), nil } //Decode 将消息解码 func Decode(reader *bufio.Reader) (string, error) { //读取消息长度 lengthByte, _ := reader.Peek(4) //读取4个字节的数据 lengthBuff := bytes.NewBuffer(lengthByte) //创建字节对象 var length int32 //把字节对象按照 小端 读取长度放入length中,然后判断 01返回err是否为空 02类容有长度 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return "", err } //Buffered返回缓冲中现有的可读取的字节数 if int32(reader.Buffered()) < length+4 { return "", err } //读取真正的消息 //定义一个数组,设定长度 pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return "", err } return string(pack[4:]), nil }
1,客户端代码——粘包解决版
package main //server服务端 import ( "bufio" "fmt" "io" "net" ) func main() { //01,启动服务 net.Listen listener, err1 := net.Listen("tcp", "127.0.0.1:20000") //net.Listen网络.监听 if err1 != nil { fmt.Println("12.0.0.1:20000 连接错误!!!") return } //02,接受连接 listener.Accept(),用 for循环建立多个请求 for { conn, err2 := listener.Accept() //listener.Accept收听.接受 if err2 != nil { fmt.Println("accept 接受请求错误!!!") return } //03,读取信息 连接对象.Read([]byte存放信息),发送客户端 go conn_(conn) } } //--------------------------使用函数------------------------------ func conn_(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) for { msg, err := proto.Decode(reader) if err == io.EOF { return } if err != nil { fmt.Println("Decode failed,err:", err) return } fmt.Println("收到client发来的消息:", msg) } }
2,client客户端代码——粘包解决版
package main //client客户端 import ( "fmt" "net" //"bufio" //"os" //"strings" ) func main() { //01,与server端建立连接 conn, err1 := net.Dial("tcp", "127.0.0.1:20000") //net.Dial网络.拨号 if err1 != nil { fmt.Println("dial 127.0.0.1:20000 failed,err") return } //02,发送数据 //var msg string /*用法1 用命令行参数os.Args发出 if len(os.Args) < 2 { msg = "hello wangye!!!" } else { msg = os.Args[1] } conn.Write([]byte(msg)) */ /*用法2 循环发出 input 用户数据 > 弊端无法过滤空格输出 for { fmt.Print("请老大发言:") fmt.Scanln(&msg) if msg == "exit" { break } conn.Write([]byte(msg)) }*/ /*用法3 用bufio.NewReader() for { reader := bufio.NewReader(os.Stdin) //从标准输入生成读对象 fmt.Print("请老大发言:") text, _ := reader.ReadString(‘\n‘) //读到换行 text = strings.TrimSpace(text) //trim space去除空格 conn.Write([]byte(text)) }*/ for i := 0; i < 20; i++ { msg := "黑鲁,黑鲁,how are you?" b, err := proto.Encode(msg) if err != nil { fmt.Println("Encode failed,err:", err) } conn.Write(b) } //03,关闭程序 defer conn.Close() } //--------------------------使用函数------------------------------
Encode
标签:std protocol 命令 拆分 nil UNC cep else listener
原文地址:https://www.cnblogs.com/shijieziben/p/14307744.html