• php中user_filter的使用


    php中user_filter的使用

    golang中io库提供了统一的流操作方法,php中存在类似功能吗?答案是有的,并且同golang相似地提供了统一的操作流(网络、

    文件、压缩数据等数据的抽象)的方法。也就是说php的流函数提供了处理不同流资源的统一接口。

    流数据各式各样,针对不同的流自然需要不同的协议,这就是流封装协议

    php中的流协议由schema://resource 组成,schema就是流封装协议,resource就是数据资源。

    file_get_contentx('http://123.abc')
    fopen('file://abc.txt', 'a')
    fgets('php://stdin')
    

    相比于完全实现自己的流封装协议(因为都替你实现好了,这里有个例子),工作中更可能用到的是在读取或写入的流的过程中对流进行写操作。这就可能使用到流上下文,作用是影响流的行为,同时不同的流封装协议有不同的上下文选项。如使用http流协议发送post请求

    $postdata = http_build_query(
        array(
            'var1' => 'some content',
            'var2' => 'doh'
        )
    );
    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/x-www-form-urlencoded',
            'content' => $postdata
        )
    );
    $context = stream_context_create($opts);
    $result = file_get_contents('http://example.com/submit.php', false, $context);
    

    同样的我们可以自定义的流过滤器影响读写流的行为,可实现修改、过滤流等功能。下面是用user_filter实现一个简单的拆包过程

    # 客户端 php已经提供了类似功能,这里只是演示,没什么实际意义的例子
    # the filter really doesn't consume the connenction's buffer in this example, so there may be repetitive content, we can totally solve the situation in next episode
    class unpack_filter extends php_user_filter
    {
        public string $data = '';
    
        public function filter($in, $out, &$consumed, $closing)
        {
            while ($bucket = stream_bucket_make_writeable($in)) {
                $this->data .= $bucket->data;
                $consumed   += $bucket->datalen;
                $p          = explode("\n", $this->data);
                // TODO 完善分包处理
                $last = array_pop($p);
                if ($last !== '') {
                    $this->data = $last;
                }
                array_walk($p, function ($pp) use ($in, $out, &$len) {
                    if (!empty($pp)) {
                        $nb  = stream_bucket_new($this->stream, 'got filtered' . $pp . "test");
                        stream_bucket_append($out, $nb);
                    }
                });
            }
            return PSFS_PASS_ON;
        }
    }
    
    $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_connect($sock, '127.0.0.1', 9503);
    
    $res = socket_export_stream($sock);
    stream_filter_register('unpack_filter', 'unpack_filter');
    stream_filter_append($res, 'unpack_filter');
    
    while (1) {
        var_dump(stream_get_line($res, 0, "test"));
    }
    
    # 服务端 复制自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 = 'abcd1234';
        // $data = pack('N', strlen($data)) . $data;
        $data = "abcd1234\n";
        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();
    

    参考内置filter

  • 相关阅读:
    抓取csdn上的各类别的文章 (制作csdn app 二)
    Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架
    MongoDB基本使用
    MongoDB之DBref(关联插入,查询,删除) 实例深入
    nginx 1.4.7 发送日志到rsyslog
    nginx 编译参数
    nginx 编译参数
    rsyslog 传输日志
    rsyslog 传输日志
    rsyslog 直接读取日志,当日志截断后,不会继续发送
  • 原文地址:https://www.cnblogs.com/alwayslinger/p/15969836.html
Copyright © 2020-2023  润新知