不灭的焱

革命尚未成功,同志仍须努力

作者:php-note.com  发布于:2017-11-28 23:35  分类:PHP库/系统/微信 

Swoole 可用于php快速开发高效的tcp/udp服务,其中tcp是用的比较多的一个场景,http虽然是基于tcp协议的,但和直接开发tcp服务还是有明显的区别的。

TCP是数据流

tcp是数据流,这是一个基本的概念,这里有两个要点:

  1. 数据没有边界

    你可以理解为水在一个水管里的流动,我们不知道哪段数据是一个我们需要的完整数据

  2. 收发有缓冲区

    比如:当水从一端流到了另一端,我们在收数据的时候,不可能每来一滴水就处理一次,这个缓冲区就相当于有了一个水桶,再接了一定的水之后内核再给数据交到用户空间,这样可以大大提升性能。

那这里就有一个问题:由于这个特性,内核无法知道哪部分数据是你想要的,所以应用层拿到数据可能是完整数据,也可能是不完整或者一部分完整、一部分不完整(粘包),那么怎样能得到想要的数据呢?

数据协议

数据协议可以理解为一种约定,按照这个约定来处理收到的数据进而得到想要的数据,这个过程就称为拆包,那问题又来了?

Web开发为什么不用考虑粘包

因为web的http可以理解为一个公共的数据协议,在实现一个web服务器的时候,就必需按照这个协议来进行数据处理,这样保证在应用层获取到数据是完整的数据,http是典型的包头+包体的这个一个约定格式,有那现几个特点:

  1. 通过\r\n\r\n来区分包头和包体

  2. 包头通过\r\n来区分不同的数据组

看个示例:

GET / HTTP/1.1

Host: www.swoole.com

Connection: keep-alive

这是一个典型的请求头,第一行约定了请求的方法(GET/POST/PUT/DELETE等)、请求地址、http协议版本, 从第二行开始,都是健:值的形式,反应到PHP里,就是$_SERVER超全局变里里 HTTP_开头的数据,由于这是GET请求,所有没有包体,如果是POST或者response响应,我们可以看到包体,包体的长度通过包头里的Content-Length参数来控制的

Swoole怎么处理粘包

swoole考虑到在粘包是一个必需处理的过程,内置了两种方案:

  1. 约定结束符

    这个类似于c里面的字符串数组,约定了\0表示字符串结束,在swoole里,可以的setting数组中,开启open_eof_check=true,并用package_eof来设置一个完整数据结尾字符。

    举个例子:

    "open_eof_check"=>true

    "package_eof" = >'swooleend',

    这里设置了package_eof = 'swooleend', 那client在每个完整数据之后再拼上swooleend之后,再发送到swoole server,swoole server就能自动识别并拼出一个完整的包。这里又隐含了两个小问题?

    a)  如果我一次收到了多个完整包怎么办?

            那可以开启 open_eof_split=>true,这样在onReceive里回调里拿到的数据就是一个完整的包了,否则需要业务层里自行explode('swooleend', $data)了,

    b)  要保证业务数据里不能出现package_eof设置的字符,否则将导致数据错误了。

  2. 自定义包头包体

    这种方式也很常见,特别是在二进制数据流中,原理是通过约定数据流的前几个字节来表示一个完整的数据有多长,从第一个数据到达之后,先通过读取固定的几个字节,解出数据包的长度,然后按这个长度继续取出后面的数据,依次循环。

    相关配置:

    'package_length_type'   => 'N',      // 数据unpack方式,这里N表示无符号32位大端长整型,更多定义可以参考:http://php.net/manual/zh/function.pack.php

    'package_length_offset'=> 0,        // 第N个字节是包长度的值

    'package_body_offset'   => 4,       // 第几个字节开始计算长度

    'package_max_length'    => 2000000,  // 协议最大长度

这个配置表示,前面4个字节是数据包长度,按照N的方式解析,最后一个配置表示数据包的最大长度,这个配置的目的是为了控制内存。

总结:

粘包处理是很多新做服务器网络编程最容易碰到的问题,特别是长期做web开发的同学,基本没有这个概念,所以通过这个思维转换,更深入的了解http协议,进而了解tcp协议,对服务器网络编程是非常有好处的。

 

 

摘自:http://guangla.lofter.com/post/1d337f35_83e279c