• 使用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 待完善
            // 此处只是示例,各位可自行完善,这种写法可能会导致缓冲区数据堆积,如果采用多路复用可能会造成IO事件的持续触发
            // 需要在应用层实现buffer
            $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()
        {
            // TODO 待完善
            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。

    我们下期再见

  • 相关阅读:
    [C语言]数据类型与计算
    [C语言]变量VS常量
    [C语言]在命令行编译执行程序
    [cocos2d-x]游戏开发基础(图)
    [cocos2d-x]移动平台游戏开发(图)
    [cocos2d-x]认识游戏开发(图)
    [jQ/PHP]再谈使用JS数组储值的运用(提交PHP处理)
    [Nginx]Nginx的基本配置与优化1(完整配置示例与虚拟主机配置)
    [JS]如何理解JS中的类和对象
    [jPlayer]一分钟部署jPlayer
  • 原文地址:https://www.cnblogs.com/alwayslinger/p/15973607.html
Copyright © 2020-2023  润新知