swoole学习之: 协程初探(三) TCP测试

昨天我们编写了协程的数据库测试代码, 几天继续撸 TCP.

我们先看一下php中packunpack这两个函数:

pack 将数据打包成二进制字符串

pack( string $format[, mixed $args[, mixed $...]] ) : string

unpack 从二进制字符串对数据进行解包

unpack( string $format, string $data[, int $offset = 0] ) : array

下面的例子中, 会使用'n'作为参数 format, 表示无符号短整型(16位,大端字节序)

$data = 'aben';
$packed = pack('n', strlen($data)) . $data;
var_dump($packed);
$unpacked = unpack('n', $packed);
var_dump($unpacked);

执行结果:

好了, 正式开始tcp操作.

use Swoole\Runtime;
use Swoole\Coroutine;
use function Swoole\Coroutine\run;

//开启协程. 自动将文件操作,sleep,mysqli,pdo,streams等都变成异步IO
Runtime::enableCoroutine();

$time_start = microtime(true);

run(function(){
    // region 测试tcp连接12.8k次

    function tcp_pack(string $data) : string
    {
        return pack('n', strlen($data)) . $data; //将数据打包成二进制字符串. 格式'n'表示无符号短整型(16位,大端字节序)
    }
    function tcp_length(string $head) : int
    {
        return unpack('n', $head)[1];//将二进制字符串解包, 取数组下标1, 表示长度
    }

    Coroutine::create(function(){
        //创建并返回一个资源流上下文
       $ctx = stream_context_create([
           'socket'=>[
                    'so_reuseaddr'=>true,//让端口释放后立即就可以被再次使用
                    'backlog'=>128//累计未完成的待处理事件
               ]
       ]);
       //创建一个socket服务
       $socket = stream_socket_server(
         'tcp://10.0.2.7:81',
         $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctx
       );
       if(!$socket){
           echo $errstr.'('.$errno.')'.PHP_EOL;
       }else{
           $i = 0;
           //接受由 stream_socket_server() 创建的套接字连接
           while($conn = stream_socket_accept($socket, 1)){
               stream_set_timeout($conn, 5);
               for($n = 100; $n--;){//100
                   //接收的数据
                   $data = fread($conn, tcp_length(fread($conn, 2)));
                   echo 'SERVER RECEIVED: '.$data.PHP_EOL;
                   assert($data == 'Hello Swoole Server #'.$n);//如果服务器返回的文字等于xxx, 则中断执行
                   //给客户端返回信息, 告知客户端循环的序号
                   fwrite($conn, tcp_pack('Hello Swoole Client #'.$n));
               }
               if( ++ $i == 128){//128
                   fclose($socket);
                   break;
               }
           }
       }
    });
    for($c = 128; $c--;){
        Coroutine::create(function(){
            //打开一个socket连接
            $fp = stream_socket_client('tcp://10.0.2.7:81', $errno, $errstr, 1);
            if(!$fp){
                echo $errstr.'('.$errno.')'.PHP_EOL;
            }else{
                stream_set_timeout($fp, 5);
                for($n = 100; $n --;){
                    //发送
                    fwrite($fp, tcp_pack('Hello Swoole Server #'.$n));
                    //接收数据
                    $data = fread($fp, tcp_length(fread($fp, 2)));
                    echo 'CLIENT RECEIVED: '.$data.PHP_EOL;
                    assert($data == 'Hello Swoole Client #'.$n);
                }
                fclose($fp);
            }
        });
    }

    //endregion

});

$time_end = microtime(true);
echo 'Time elapsed: '.($time_end - $time_start).' s'.PHP_EOL;

未完待续

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章