go TCP 粘包原理和解决方案
1 为什么会出现粘包
主要原因是tcp 数据传递模式是留模式,在长连接过程中可以进行多次收发。数据粘包可以发生在客户端和服务端。
2 解决办法
出现粘包的关键在于不确定包的大小,因此可以通过封包将把的内容长度封装在包头,用固定长度的值来存储包内容长度。自己封装一个数据传输协议。如下:
package protoimport ("bufio""bytes""encoding/binary"
)// Encode 将消息编码
func Encode(message string) ([]byte, error) {var length = int32(len(message)) // 读取消息的长度,转换成int32类型(占4个字节)var pkg = new(bytes.Buffer) // 定义一个空的bytes 缓冲区// 写入消息头err := binary.Write(pkg, binary.LittleEndian, length) //通过小端序列的方式把length 写到pkg。binary.LittleEndian 为编码格式if err != nil {return nil, err}// 写入消息实体err = binary.Write(pkg, binary.LittleEndian, []byte(message)) //在通过小端序列的方式把真实的包内容写入bytes,封装成一个包。if err != nil {return nil, err}return pkg.Bytes(), nil // 返回封装好的包
}// Decode 解码消息
func Decode(reader *bufio.Reader) (string, error) {lengthByte, _ := reader.Peek(4) // 读取前4个字节的数据,及包的内容长度,endoce 里面的length。Peek的方式读取内容,是不会清掉缓存的lengthBuff := bytes.NewBuffer(lengthByte) //定义一个以lengthByte为内容的bytes缓冲区var length int32err := binary.Read(lengthBuff, binary.LittleEndian, &length)// 将lengthBuff 的内容写到length里面。这里要相应解码才能读取到length的内容if err != nil {return "", err}// Buffered返回缓冲中现有的可读取的字节数。前面用Peek读取,所以这里数据内容应该大于length+4if 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 //返回去掉length的字符串
}
后续在客户端发送消息的时候编码,读写的时候解码就行了
// 客户端
msg := `Hello, Hello. How are you?`
data, err := proto.Encode(msg)
conn.Write(data)
//服务端
msg, err := proto.Decode(reader)
if err == io.EOF {return
}
if err != nil {fmt.Println("decode msg failed, err:", err)return
}
go TCP 粘包原理和解决方案相关推荐
- Socket编程(4)TCP粘包问题及解决方案
① TCP是个流协议,它存在粘包问题 TCP是一个基于字节流的传输服务,"流"意味着TCP所传输的数据是没有边界的.这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的.T ...
- TCP粘包|拆包和解决方案
1 产生原因 TCP是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化算法(Nagle ...
- TCP粘包问题的解决方案01——自定义包体
粘包问题:应用层要发送数据,需要调用write函数将数据发送到套接口发送缓冲区.如果应用层数据大小大于SO_SNDBUF,那么,可能产生这样一种情况,应用层的数据一部分已经被发送了,还有一部分还在套接 ...
- Socket编程 TCP粘包问题及解决方案
① TCP是个流协议,它存在粘包问题 TCP是一个基于字节流的传输服务,"流"意味着TCP所传输的数据是没有边界的.这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的.T ...
- TCP 粘包和拆包及解决方案
TCP 粘包和拆包基本介绍 1.TCP 是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使 ...
- 20-Netty TCP 粘包和拆包及解决方案
TCP粘包和拆包的基本介绍 TCP是面向连接的, 面向流的, 提供可靠性服务, 收发两端(客户端和服务器端) 都有一一成对的Socket,因此发送端为了将多个发给接收端的包, 更有效的发给对方, 使用 ...
- netty编解码器注意事项及粘包和拆包解决方案
netty编解码器 当 Netty 发送或者接受一个消息的时候,就将会发生一次数据转换.入站消息会被解码:从字节转换为另一种格式(比如 java 对象):如果是出站消息,它会被编码成字节. Netty ...
- TCP粘包、半包原理及解决方案
引言:TCP协议是网络通信协议中十分重要的协议,相比于UDP协议来说,它是一个可靠的传输协议,并且是一个面向数据流的协议:所谓面向数据流,其实是指数据传输是以流式的方式传输,这些传输的数据就像一条河里 ...
- Netty框架之TCP粘包/半包解决方案
Netty框架之TCP粘包/半包解决方案 一.TCP粘包 二.TCP半包 三.TCP粘包/半包解决方案 1.FixedLengthFrameDecoder定长解析器 2.LineBasedFrameD ...
- Netty4实战 - TCP粘包拆包解决方案
Netty4实战 - TCP粘包&拆包解决方案 参考文章: (1)Netty4实战 - TCP粘包&拆包解决方案 (2)https://www.cnblogs.com/hunrry/p ...
最新文章
- 更多的结构化命令(第十三章)
- 年底了,游戏大作连连
- mysql group_concat去重_MySQL group_concat() 函数用法
- Android接口一般定义格式,Android开发规范
- USB2.0学习笔记连载(一):CY7C68013特性简介
- Python 和 egg 文件
- python爬虫cookie池搭建_爬虫——cookies池的搭建
- matlab中目录的相关操作
- steam快速换号工具易语言源码 附成品
- flash电脑安装包_flash控件下载特色众多flash控件下载使用评估
- 在哪可以找c语言编程的答案,c语言程序设计课后习题答案.doc
- [SUCTF 2019]EasyWeb 1
- 植被覆盖指数计算教程(ENVI)
- 计算机纳入高考作文,高考作文听人家说今年的高考作文是用计算机批 – 手机爱问...
- mac pro 系统升级带来的问题
- 陈睿提供2009-06-19
- Java学习第二十四天
- c语言查表法编程流水灯,通过查表法的流水灯汇编程序
- unbutu服务器误删文件,Ubuntu误删系统文件修复办法
- ETH 2.0新纪元开启,究竟能带来什么?
热门文章
- pdca实施的流程图_思维导图丨《高效PDCA工作术》流程图
- 许可证加密的WMV文件破解
- WordPress主题 LightSNS v1.6.60 强大的社交系统SNS主题(免受权)
- mix2线刷开发板救砖_小米MIX2官方原厂系统rom线刷刷机包降级包下载8.10.25版
- Unity经验·任意位置的透视问题
- MFC基础之字符集,Unicode字符集,多字节字符集
- 用php打印出日历_PHP完成一个日历
- 在FireFox中使用IE Tab插件
- 国家网络信息安全战略三步曲
- C++判断是否为一个凹多边形