+
80
-

swoole中tcp传输如何按固定包数据结构传输?

php

swoole中tcp传输如何按固定包数据结构传输?


网友回复

+
0
-

swoole提供了内置包长检测的方法,该方法提供了固定包头 + 包体这种格式协议的解析。

启用后,可以保证 Worker 进程 onReceive 每次都会收到一个完整的数据包。

长度检测协议,只需要计算一次长度,数据处理仅进行指针偏移,性能非常高,推荐使用。 可见官方是推荐使用这种方式的,就是配置比其他方案要复杂一些, 首先贴一下配置: $server->set([ // 打开包长检测特性 'package_length_check' => true, // 包头中某个字段作为包长度的值,底层支持了 10 种长度类型。可参考 pack() 方法 'package_length_type' => 'N', // length 长度值在包头的第几个字节。 'package_length_offset' => 8, // 从第几个字节开始计算长度,一般有 2 种情况: //length 的值包含了整个包(包头 + 包体),package_body_offset 为 0 //包头长度为 N 字节,length 的值不包含包头,仅包含包体,package_body_offset 设置为 N 'package_body_offset' => 16, // 设置最大数据包尺寸,单位为字节 'package_max_length' => 81920 ]); 下面是一个数据包结构例子,可以很好的体现了字段含义。

下面看具体的示例代码:

tcp服务端代码

<?php
$serv = new Swoole\Server('127.0.0.1', 9502);
$serv->set([
    'open_length_check'     => true,
      'package_max_length'    => 81920,
      'package_length_type'   => 'N',
      'package_length_offset' => 8,
      'package_body_offset'   => 16,    
]);

$serv->on('connect', function($server, $fd){
    echo $fd. " Connect !".PHP_EOL;
});

$serv->on('receive', function($server, $fd, $from_id, $data){
     $length = unpack('N', $data)[1];
        echo "Length:".$length.PHP_EOL;
        $msg = substr($data, -$length);
        echo "Msg:".$msg.PHP_EOL;
    var_dump($data);            // 源数据
    $tmp = unpack("Ntype/Nuid/Nlength", $data);
    $unpacking = unpack("Ntype/Nuid/Nlength/Nserid/a{$tmp['length']}body", $data);
    var_dump($unpacking);        // 解包后数据
    $server->send($fd, " Server Receive Data: ". $unpacking['body']);
});


$serv->on('close', function($server){

});

$serv->start();

tcp客户端代码

$client = new Swoole\Client(SWOOLE_SOCK_TCP);

$data = "123456789012345678901234567890";
$type = 0x30;
$uid = 0x123;
$length = strlen($data);
$serid = 0x15;
$head = pack("N4", $type, $uid, $length, $serid);
$body = pack("a{$length}", $data);
$message = $head.$body;


if ($client->connect('127.0.0.1', 9502, -1)) {
    $client->send($message);
    echo $client->recv();
}

$client->close();

我知道答案,我要回答