swoole學習之: 協程初探(四) udp測試

儘可能的把內容寫入註釋了

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 測試udp連接12.8k次
    //服務端
    Coroutine::create(function(){
        $socket = new Swoole\Coroutine\Socket(AF_INET, SOCK_DGRAM, 0); //domain, type, protocol
        // domain=AF_INET, 使用ipv4通信
        // type=SOCK_DGRAM, 無保障的面向消息的socket,主要用於在網絡上發廣播信息
        $socket->bind('127.0.0.1', 9503);//綁定監聽的ip和端口
        $client_map = [];
        for($c = 128; $c--;){
            for($n = 0; $n < 100; $n++){
                //接收數據
                $recv = $socket->recvfrom($peer);// $peer: 與套接字關聯的外地協議地址, 包含`address`和`port`的一個數組
                //var_dump($peer);
                $client_uid = $peer['address'].':'.$peer['port'];//客戶端地址:端口
                $id = $client_map[$client_uid] = ($client_map[$client_uid] ?? -1) + 1;
                echo 'SERVER RECEIVED :' . $recv . "\t id=".$id . PHP_EOL;
                assert($recv === 'Client: Hello #' . $id);//如果接收到的信息不是xxx, 則終止(不會拋出"Warning")
                //給客戶端發送信息
                $socket->sendto($peer['address'], $peer['port'], 'Server: Hello #' . $id);
            }
        }
        $socket->close();
    });
    //客戶端
    for($c = 128; $c--;){
        Coroutine::create(function()use($c){
           $fp = stream_socket_client('udp://127.0.0.1:9503', $errno, $errstr, 1);//連接udp服務器, 超時時間1s
           if(!$fp){
               echo $errstr.'('.$errno.')';//連接失敗, 在客戶端打印錯誤信息
           }else{
               for($n = 0; $n < 100; $n ++){//100
                   //發送
                   fwrite($fp, 'Client: Hello #'.$n);
                   //接收數據
                   $recv = fread($fp, 1024);
                   $remote_socket_name = stream_socket_get_name($fp, true);//獲取遠程的套接字名稱
                   list($address, $port) = explode(':', $remote_socket_name);//把拆解後的一維數組賦給變量$address, $port
                   echo 'c=' . $c . ', n=' . $n . ' CLIENT RECEIVED: ' . $recv . "\t";
                   echo 'remote_socket_name:' . $remote_socket_name . "\t" . $address . ':' . $port . PHP_EOL;
                   assert($address === '127.0.0.1' && (int)$port === 9503, 'ADDR OR PORT NOT MATCH');//如果地址不是127.0.0.1或者端口不是9503, 則終止(不會拋出"Warning")
                   assert($recv === 'Server: Hello #'.$n, 'RESPONSE NOT MATCH');//如果接收到的信息不是xxx, 則終止(不會拋出"Warning")
               }
               fclose($fp);
           }
        });
    }

    //endregion
});

$time_end = microtime(true);
echo 'Time elapsed: '.($time_end - $time_start).' s'.PHP_EOL;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章