发布网友 发布时间:2023-07-05 21:15
共1个回答
热心网友 时间:2023-11-02 15:59
TCP 协议是面向连接,可靠的流式协议,当 Server 去 Read 的时候,每次读到的数据都不一定是完整的,该方法会返回读到的字节数,因此,当我们写 Server 的时候,什么时候去回调用户设置的 callback ?也就是怎么样保证每次都能拿到一个完整的包数据,这个就是”粘包“问题的由来。
传统的,有两种方法解决。一是分隔符协议,即每条消息结尾设置固定分隔符,Server 读到分隔符就认为读到了完整的包数据;二是长度协议,即在每个消息头部设置固定长度的字段,表征消息长度,再往后读取该长度的消息即可。
目前长度协议用的较多,因为分隔符协议需要 Server 不停的检测,很耗费性能。长度协议实现中比较重要的点是头部的长度以及字节序,2个字节可表示 2^16-1个字节的内容,如果不够,那就上4字节,字节序相关的只是可以参考: ”字节序“是什么鬼?
先来个没处理粘包的:
common/server.go:
测试一下:
因为每次只读5个字节,可以明显看到消息”乱了“,但就算把这个值增大,你只要是设置了,就会存在这个问题。
delimeter/server.go:
还是拿上个测试脚本跑,结果:
这次看到每个消息长度不一样,但是都是”完整的“。
length/server.go:
client 也得相应调整:
测试结果:
效果跟分隔符协议一样,都可以解决”粘包“问题。
只要是 TCP 协议,任何语言都需要处理 ”粘包“ 问题,我们用 PHP 写一个客户端测试一下:
完美!
只有在直接使用 TCP 协议才存在 "粘包" 问题,其上层应用层协议比如 HTTP ,已经帮我们处理好了,无需关注这些底层,但是我们自己实现一个自定义协议,就必须考虑这些细节了。
2021-03-08