Swoole TCP 流数据边界问题解决方案
1. 数据发送过程我的官方群点击此处。 首先由客户端将数据发往缓冲区 (服务端并不是直接收到的), 对于客户端来说,这次的数据即是发送成功了, 对于服务端是否真正的收到他是不知道的, 然后再由服务端从缓冲区中读取数据。图解: ? ? ? 2. 什么是数据边界? 因为 TCP 是流式传输,对于服务端来说并不知道此时在缓冲区内的数据是一次请求还是两次请求的,所以在服务端接收数据时需要根据指定字符或约定长度来对数据进行分包,这个分包的标志即是数据边界。否则可能会出现一次读取两条或多条数据,造成读取、解析数据出错。 ? ? ? 2.1 代码演示可以用代码实现一下,假设客户端死循环往缓冲区不停输入 “1”,即相当于每次的报文内容都是 1, 那么在服务端读取时收到的数据就是随机长度的。 客户端代码
服务端代码
运行结果? ? ? 可以看到运行结果,服务端获取到的数据完全是随机的,有长有短,那么接下来我们说下如何解决这个问题。 ? 3.EOF 解决方案第一种解决方案类似于我们 http 请求头的分隔符,在每次发送的数据包结尾处使用 rn (可以配置) 来结尾, 当服务端从缓冲区中读取数据, 根据指定字符来分割数据包,EOF 有两种配置方案: 3.1 open_eof_check首先放出配置方式:
这种配置方式会对客户端发来的数据包进行检测, 当发现结尾是 rn 时,才会投递给 worker 进程, 也就是我们的 onReceive 回调,否则会一直拼接数据包,直到超出缓冲区或者超时才终止。 但此方法有一个问题是可能会一次性收到多个数据包,因为他是从数据包的结尾处来进行检查的,在数据内容中存在 rn 时程序并不会发现,需要我们自己在应用代码中再次使用 rn 来拆分数据包。 客户端运行代码
服务端代码
? 运行结果? ? ? 3.2 open_eof_split配置方式:
这种配置方式,服务端会对客户端发来的数据逐个字符进行检查,遇到 rn 就发送给 worker 进程,可以有效实现分包,但缺点是性能比较差。 运行结果:可以看到每次接收到一个 Hello World(代码我就不贴了, 只把服务端 set 配置改一下, 其他都一样) ? ? 3.3 open_eof_check 和 open_eof_split 差异?
4. 固定包头 + 包体解决方案引用一段官方文档的描述: 包长检测提供了固定包头 + 包体这种格式协议的解析。启用后,可以保证 Worker 进程 onReceive 每次都会收到一个完整的数据包。 ? 可见官方是推荐使用这种方式的,就是配置比其他方案要复杂一些, 首先贴一下配置:
下面是一个数据包结构例子,可以很好的体现了字段含义。 ? ? 以上通信协议的设计中,包头长度为 4 个整型,16 字节,length 长度值在第 3 个整型处。因此 package_length_offset 设置为 8,0-3 字节为 type,4-7 字节为 uid,8-11 字节为 length,12-15 字节为 serid。 ? 下面来说一下代码实现: 客户端代码: ?
服务端代码:
客户端运行结果? ? ? 服务端运行结果? ? ? 可以看到 客户端成功的把发送的数据回显, 服务端也打印出了接收到的所有数据, 其中有些字段在发送时是 16 进制的, 所以服务端在接收到之后需要进行进制转换, 我这里没有进行转换, 所以显示的数据是 10 进制的。 5. 总结? 通过对比可以看出使用固定包头 + 包体的方式是效率最高的一种, 因为他是按照固定长度去读取的。期间专门去了解了 pack 函数的使用方法,但也不确定这么写到底对不对,如果有其他了解的仁兄可以慷慨解答一下,网上相关资料有点少,官方文档上也只给出了几个字段的释义。 ? 6. 扩展知识:? 6.1 字节序计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。 ? 举例来说,数值 0x2211 使用两个字节储存:高位字节是 0x22,低位字节是 0x11。 ?
这个前和后指的是内存地址,计算机处理字节时是不知道高低字节之分的,它只知道按顺序读取字节,先读第一个字节,再读第二个字节。 例如: 0x1234567 的读取顺序: : ? ? ? 参考资料: ? www.ruanyifeng.com/blog/2016/11/byt... ? www.cnblogs.com/nr-zhang/p/9989390... ? Swoole4 文档... ? 推荐观看:swoolePHP—swoole通往大神修炼之路:av77924246 手把手教你用swoole+websocket实现户外监控直播(总集篇):av79087951 教你用swoole开发网络游戏:av79264440 PHP高级技术手写swoole分布式框架:av78383962 PHP高级技术手写swoole分布式框架(二):av78632435 PHP高级技术手写swoole分布式框架(三):av78748923 PHP高级技术手写swoole分布式框架(框架优化):av78856427 PHP高级技术手写swoole分布式框架(分布式RPC):av79012272 用swoole实现消息推送:av79874641 swoole+docker+redis主从复制及读写分离av78781841 ? 更多学习内容请访问: 腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新) ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |