1. 程式人生 > 其它 >使用streamwrapper進行自定義解包封包

使用streamwrapper進行自定義解包封包

使用streamwrapper進行自定義解包封包

streamWrapper class

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。

我們下期再見