swoole中tcp传输如何按固定包数据结构传输?
网友回复
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();