骑驴找蚂蚁

全干工程师

Swoole发包(pack)到服务端数据长度不一致问题解决

由于长度不一致,导致判断内容是否完整失效(没有主动关闭)而连接超时失败(造成这种现象要你的数据包够长服务端会分段获取内容).下面这段代码是客户的事例:

$ip = '127.0.0.1';
$swoole = new swoole_client(SWOOLE_TCP);
$swoole->connect($ip, 9201, 10);
$content = str_repeat('Hello world ', 1000);
//包长在加包数据
//@see http://php.net/manual/en/function.pack.php
echo strlen($content);
$data = pack('Na*', strlen($content), $content);
$swoole->send($data);
$swoole->close();

下面是服务端代码:

$http = new swoole_server("0.0.0.0", 9201, SWOOLE_BASE, SWOOLE_SOCK_TCP);
$http->set([
    'worker_num' => 4,
    'daemonize' => false,
    /**
    'package_max_length' => 1024 * 1024 * 2,
    'open_length_check'=> true,
    'package_length_offset' => 0,
    'package_body_offset' => 4,
    'package_length_type' => 'N'
    **/
]);

$http->on('connect', function($serv, $fd) {
    echo "client connection\n";
});

$datas = ['len' => [], 'data' => []];
$http->on('receive', function(swoole_server $serv, $fd, $from_id, $data) use(&$datas) {
    $arr = unpack("Nlen/a*string", $data);
    if (!isset($datas['len'][$fd])) {
       $datas['len'][$fd] = $arr['len'];
    }
    
    if (!isset($datas['data'][$fd])) {
       $datas['data'][$fd] = $arr['string'];
    } else {
       $datas['data'][$fd] .= $arr['string'];
    }
    $len = $datas['len'][$fd];
    $strlen = strlen($datas['data'][$fd]);    
    echo $len, PHP_EOL;
    echo $strlen, PHP_EOL;
    if ($strlen >= $len) {
        $serv->send($fd,  $datas['data'][$fd], $from_id);
        unset($datas['len'][$fd]);
        unset($datas['data'][$fd]);
        $serv->close($fd);
    }
});

$http->on('close', function($serv, $fd) {
    echo "exit... \n";
});

$http->start();

执行结果:

客户端:QQ图片20170628185705

服务端:QQ图片20170628185735

可以看到数据大小为2W字节, 但是服务器拼接大小后只有19992字节了.

开启以下代码:

$http->set([
    'worker_num' => 4,
    'daemonize' => false,
    'package_max_length' => 1024 * 1024 * 2,
    'open_length_check'=> true,
    'package_length_offset' => 0,
    'package_body_offset' => 4,
    'package_length_type' => 'N'
]);

意思是设置长度检查,长度开始位置,长度偏移量为4个字节,我们N为整型4个字节.

设置之后的结果:

QQ图片20170628191032

数据是一次性接收完整.

留言