尽可能的把内容写入注释了
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;