使用streamwrapper進行自定義解包封包
阿新 • • 發佈:2022-03-06
使用streamwrapper進行自定義解包封包
stream wrapper和filter的關係:stream wrapper能夠使resource流化,比如http://www.baidu.com/index.php,php內建的http stream wrapper就會將後面的resource流化,讓php能夠以流的形式操作資源,而filter是用來操縱這些流(meta-stream)的。
基本使用如下:
# php://filter/read=[filter]/resource=[stream] $input = fopen('php://filter/read=string.toupper/resource=php://stdin', 'r'); while (false !== ($line = fgets($input))) { echo $line; } # 我們從$input讀取的就是經過filter操作後的大寫資料
示例如下:實現通過fgets每次讀取一條完成訊息的功能
# 客戶端 wrapper class UnpackWrapper { public const Name = 'myunpack'; private $resource; // fopen('myunpack://127.0.0.1:9503', 'r') // fgets() 返回一條完整的資料 public function stream_open($path, $mode, $options, &$opened_path) { if (!$this->resource) { $addr = str_replace(self::Name, 'tcp', $path); $this->resource = stream_socket_client($addr); } return true; } public function stream_read($count) { // TODO 待完善 $head = fread($this->resource, 4); $len = unpack('N', $head)[1]; $data = fread($this->resource, $len); return $data . "\n"; } public function stream_close() { @fclose($this->resource); } public function stream_eof() { return is_resource($this->resource) ? false : true; } } stream_register_wrapper(UnpackWrapper::Name, UnpackWrapper::class); var_dump(stream_get_wrappers()); $fp = fopen('myunpack://127.0.0.1:9503', 'r'); while (1) { $data = fgets($fp); var_dump($data); sleep(1); }
# 服務端程式碼複製於swoole官網 $server = new Swoole\Server('127.0.0.1', 9503); $server->on('start', function ($server) { echo "TCP Server is started at tcp://127.0.0.1:9503\n"; }); $server->on('connect', function ($server, $fd) { $data = 'abcd'; $data = pack('N', strlen($data)) . $data; for ($i = 0; $i < 10000; $i++) { $server->send($fd, $data); } }); $server->on('receive', function ($server, $fd, $reactor_id, $data) { $server->send($fd, "Swoole: {$data}"); }); $server->on('close', function ($server, $fd) { echo "connection close: {$fd}\n"; }); $server->start();
以上只是展示了確實存在通過自定義streamwrapper進行拆解包的可能,感興趣的可以自行完善,並且實現一個封包的wrapper。
我們下期再見