unix网络io模型之多路复用->select(三)
本文最重要的函数:stream_select,模型也是基于这个函数来实现的
其实就是把所建立的socket放到一个池子里面(这个池子是有最大容量的),然后再去池子查询它们的状态,通过状态来判断和它们通信。
创建以下文件和文件夹
Worker.php
<?php
namespace Ztms\Muliplexing;
use Ztms\WorkerBase;
/**
*多路复用
*/
class Worker extends WorkerBase
{
protected $sockets = [];
public function __construct($host, $port)
{
parent::__construct($host, $port);
stream_set_blocking($this->server, 0);
// 记录服务的socket
$this->sockets[(int) $this->server] = $this->server;
}
protected function accept()
{
while (true) {
$reads = $this->sockets;
// 检测sockets集合中的socket资源的状态
\stream_select($reads, $w, $e, 60);
foreach ($reads as $key => $socket) {
if ($socket == $this->server) {
// 有新的连接
$conn = $this->createConn();
if ($conn) {
$this->sockets[(int) $conn] = $conn;
} else {
var_dump("连接建立不成功");
}
} else {
// 进行消息通信
$this->sendMessage($socket);
}
}
}
}
// 创建连接
protected function createConn()
{
// 监听是否存在连接
$conn = stream_socket_accept($this->server);
if (!empty($conn)) {
// 触发建立连接事件
$this->events['connect']($this, $conn);
return $conn;
}
return null;
}
// 发送信息
protected function sendMessage($conn)
{
// 接收服务的信息
$data = fread($conn, 65535);
var_dump($data);
if ('' === $data || false === $data) {
$this->checkConn($data, $conn);
} else {
$this->events['receive']($this, $conn, $data);
}
}
// 校验连接
protected function checkConn($buffer, $conn)
{
if (\strlen($buffer) === 0) {
if (! \get_resource_type($conn) == "Unknown"){
// 断开连接
$this->close($conn);
}
\call_user_func($this->events['close'], $this, $conn );
unset($this->sockets[(int) $conn]);
}
}
}
?server.php
<?php
require_once __DIR__."/../../vendor/autoload.php";
use Ztms\Muliplexing\Worker;
$server = new Worker('0.0.0.0', 9500);
$server->on('connect', function($server, $client){
var_dump("成功建立连接");
});
$server->on('receive', function(Worker $server, $client, $data){
$server->send($client, "hi");
// $server->close($client);
});
$server->on('close', function($server, $client){
var_dump($client, "连接断开");
});
$server->start();
client.php
<?php
require_once __DIR__."/../../vendor/autoload.php";
// 连接服务端
$fp = stream_socket_client("tcp://192.168.0.100:9500");
fwrite($fp, "hello");
var_dump(fread($fp, 65535));
// sleep(10);
// fwrite($fp, "第二个消息");
// var_dump(fread($fp, 65535));
它和阻塞io模型最大的区别是,阻塞模型只能阻塞一个io,而io复用能阻塞多个io(所以叫多路复用),这就是它们最大的区别。
举例:在一个群里,你们发现一个好看的妹子,于是纷纷加她微信,可是微信有限制,一下做多可以1024个人加,然后这个妹子就发现有这么多人加他,她就一个个点通过,然后你们竟然啥也不干,硬生生的等她点通过,直到等到你自己被通过了,你才露出了笑容。
|