1.7.3 固定包头+包体协议自动分包

swoole-1.7.3版本重构了length_check特性的代码,对于固定包头+包体格式的协议可以直接在master进程中进行分包和组包,worker进程中可以一次性收到一个完整的包。配合dispatch_mode = 1或3,swoole提供了一个强大的半异步/半同步服务器模型。带来的好处是:

  • C扩展层进行协议的处理,性能最佳,原PHP代码虽然也可以实现协议处理,但需要耗费较多CPU
  • TCP连接与业务逻辑分离,有效利用所有Worker进程,即使只有1个TCP连接,也可以利用所有Worker

使用方法:

使用也很简单,仅需$serv->set中增加参数即可。

open_length_check => true

打开包长检测特性

package_length_type => 'N'

长度字段的类型,固定包头中用一个4字节或2字节表示包体长度。类型是一个字符,详情参见php的pack函数文档 比较常用的类型为:

  • N 4字节网络字节序,最大为2^32
  • n 2字节网络字节序,最大为65536

package_length_offset => 10

从第几个字节开始是长度,比如包头长度为120字节,第10个字节为长度值,这里填入9(从0开始计数)

package_body_offset => 120

从第几个字节开始计算长度,比如包头为长度为120字节,第10个字节为长度值,包体长度为1000。如果长度包含包头,这里填入0,如果不包含包头,这里填入120

package_max_length => 800000

最大允许的包长度。因为在一个请求包完整接收前,需要将所有数据保存在内存中,所以需要做保护。避免内存占用过大。

配置分发策略

dispatch_mode = 1 或 3 1:轮询分配,会逐个分配到所有worker,3:争抢分配,仅分配给空闲状态的worker



  • Karl

    测试程序如下,CLI模式运行(PHP 5.5.9-1ubuntu4.3 (cli) (built: Jul 7 2014 16:36:58) set(array( 'open_length_check' => true, 'package_length_type' => 'N', 'package_length_offset' => 0, 'package_max_length' => 800000, 'worker_num' => 8, //工作进程数量 'daemonize' => false, //是否作为守护进程 )); $serv->on('connect', function ($serv, $fd){ echo "Client:Connect.\n"; }); $serv->on('receive', function ($serv, $fd, $from_id, $data) { $serv->send($fd, 'Swoole: '.$data); $serv->close($fd); }); $serv->on('close', function ($serv, $fd) { echo "Client: Close.\n"; }); $serv->start(); ?>

    SHELL:telnet localhost 127.0.0.1 9501 Connected to localhost. Escape character is '^]'. > <

    ? KK Connection closed by foreign host. 应该是长度判断出错直接段错误退出。 [2014-07-11 13:57:35] WARN swReactorThread_get_package_length: Invalid package [length=606348301]. 段错误 (核心已转储)

  • Karl

    'open_length_check' => true 这个引起的,是我参数没选对吗? 我的要求是包头四个字节+内容,长度包括包头本身

  • ibrahim

    package_body_offset 没有设置的原因吧?

  • 屏风山下的猎人

    嗯,自己测了一下,每次也是报这样的错误

  • 朝阳

    有测试成功的,给我个小例子

  • 阿呆

    open_length_check=>true,开启后,请问后面的长度偏移量设置那些参数不写,有啥影响不,我参数都设置后,我onreceive收不到数据了,没报错