【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】

前言

上节课主要讲到了基础的5大io模型,以及阻塞io模型的代码体验。通过curl http://127.0.0.1:9501可以访问请求,但是通过浏览器访问就访问不了了,这是咋回事呢?

暴力方式实现长连接

对于浏览器访问不了的情况是因为,浏览器是http协议,而服务是tcp协议,那如何让tcp协议和http协议直接进行通信呢?

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第1张图片

对于浏览器来说,重要的一点主要是响应的头部。

当一个网站访问不到,会是因为哪些原因呢?

端口(检测端口,防火墙开放的端口),是否有异常(日志查看),协议是否一致。

对于上面浏览器不能访问的问题,我们可以在服务端发送给客户端数据时,添加响应头信息来解决。

代码片段:

public function send($conn,$data)

{

$header = "HTTP/1.1 200 OK\r\n";

$header .= "Content-Type:text/html;charset=UTF-8\r\n";

$header .= "Connection:keep-alive\r\n";

$header .= "Content-length:".strlen($data)."\r\n\r\n";

$data =$header.$data;

fwrite($conn,$data);

}

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第2张图片

还有一个问题是,当前的这个阻塞io模型,不能支持长连接,如何实现呢?

在服务端,将主动关闭连接的注释掉,客户端以轮询的方式不断向服务端发送数据。这种粗暴的方式去简单实现长连接(不会在实际代码中使用)。当然我们也可以通过心跳检测机制去实现长连接。

非阻塞模型

问题演示

stream_set_blocking 这个函数主要是用来设置阻塞或非阻塞模型,非阻塞影响的是fwrite和fread,不影响stream_socket_accept。

代码演示:

worker.php 还是阻塞模型

namespace zjl\io\NoBlocking;

 

/**

* 用户连接服务

*/

class Worker

{

/**

* 自定义服务的事件注册函数

* 闭包函数

* @var null

*/

public $onReceive = null;

public $onConnect = null;

public $onClose = null;

//连接

public $socket = null;

 

public function __construct($socket_address)

{

$this->socket = stream_socket_server($socket_address);

echo $socket_address."\n";

}

 

/**

* 处理事情

*/

public function accept()

{

//接收连接,处理事情

while(true)

{

$client = @stream_socket_accept($this->socket);

//判断是不是闭包

if(is_callable($this->onConnect)){

//执行闭包函数

($this->onConnect)($this,$client);

}

$data = fread($client,65535);

if(is_callable($this->onReceive)){

//执行闭包函数

($this->onReceive)($this,$client,$data);

}

//处理完关闭连接

fclose($client);

}

}

public function send($conn,$data)

{

fwrite($conn,$data);

}

//启动服务

public function start()

{

$this->accept();

}

}

 

server.php 做一个延迟效果

require __DIR__."/../../vendor/autoload.php";

use zjl\io\NoBlocking\Worker;

 

$host = "tcp://0.0.0.0:9501";

$server = new Worker($host);

 

/*//连接服务

$server->onConnect = function ($server,$client){

echo "有一个连接进来\n";

var_dump($client);

};*/

//接收和处理信息

$server->onReceive = function ($server,$client,$data){

/*echo "给连接发送信息\n";*/

sleep(4);

$server->send($client,"hello world client \n");

};

$server->start();

 

客户端 发送一条数据 看效果

//建立连接

$client = stream_socket_client("tcp://127.0.0.1:9501");

$new = time();

 

fwrite($client,"hello world");

var_dump(fread($client,65535));

 

echo "其他业务\n";

echo time() - $new."\n";

 

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第3张图片

这个时候发现,客户端必须等待服务端执行完之后,才能继续下面的程序,这样阻塞的情况很不好,我们可以在客户端设置成 非阻塞的,看看会出现什么情况?

客户端代码:

//建立连接

$client = stream_socket_client("tcp://127.0.0.1:9501");

//设置成非阻塞模式

stream_set_blocking($client,0);

$new = time();

 

fwrite($client,"hello world");

var_dump(fread($client,65535));

 

echo "其他业务\n";

echo time() - $new."\n";

 

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第4张图片

客户端不阻塞,但是没用数据。这个时候再客户端定时访问内核空间是否存在数据

//建立连接

$client = stream_socket_client("tcp://127.0.0.1:9501");

//设置成非阻塞模式

stream_set_blocking($client,0);

$new = time();

 

fwrite($client,"hello world");

 

echo "其他业务\n";

echo time() - $new."\n";

 

while(!feof($client))

{

var_dump(fread($client,65535));

sleep(1);

}

这就实现了非阻塞IO模型,只需要在客户端设置一下stream_set_blocking($client,0);

缺点:非阻塞模型 需要不断轮询内核,就会造成资源的消耗。

stream_select

通过轮询的方式帮助我们去查找socket是否为可用的状态。因为io多路复用模型是有多个socket连接,但不知道哪个连接是可用的状态还是忙的状态,这就需要stream_select来检测哪个socket连接是可用的。

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第5张图片

由于stream_select函数里的参数$read,$write,$except都是使用统一变量地址引用&,所以检测出可用的socket连接时,都会保存在对应的变量里。由于stream_select函数的返回值不可靠,所以直接遍历变量参数,获取可用的socket连接。

演示:

客户端

$client = stream_socket_client("tcp://127.0.0.1:9501");

//设置成非阻塞模式

stream_set_blocking($client,0);

$new = time();

 

fwrite($client,"hello world");

 

echo "其他业务\n";

echo time() - $new."\n";

 

$read = $write = $except = null;

while(!feof($client))

{

$read[] = $client;

fread($client,65535);

//var_dump(fread($client,65535));

sleep(1);

echo "检测socket";

var_dump(stream_select($read,$write,$except,1));

}

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第6张图片

stream_select 会根据数据去检测可用的socket

0表示可用,1表示忙碌

可用的socket会保存在$read数组里

通常会foreach遍历这个$read数组

多路复用IO模型

思路:

1.stream_select 可用检测 socket_client,socket_server,socket_accept

$scokets = [];记录保存很多个socket

$read = $sockets;

2.stream_select函数中的参数$read返回可用socket连接这样的一个数组

$read存的为可用的socket连接

 

多路复用io模型的实现,就会有多个socket,在进行数据读取时,若没有数据时,就会出现阻塞的情况,这个就需要stream_set_blocking()函数来设置成非阻塞的,来解决阻塞问题。

多路复用模型本质也是实现非阻塞模型。

代码实现:

Worker.php

namespace zjl\io\Multi;

 

/**

* 用户连接服务

*/

class Worker

{

/**

* 自定义服务的事件注册函数

* 闭包函数

* @var null

*/

public $onReceive = null;

public $onConnect = null;

public $onClose = null;

 

public $sockets = [];

//连接

public $socket = null;

 

public function __construct($socket_address)

{

$this->socket = stream_socket_server($socket_address);

//这里需要设置为非阻塞的状态

stream_set_blocking($this->socket,0);

//这里描述符(int)$this->socket是唯一的

//server也有忙的时候,所以也要放在池子里

$this->sockets[(int)$this->socket] = $this->socket;

echo $socket_address."\n";

}

 

/**

* 处理事情

*/

public function accept()

{

//接收连接,处理事情

while(true)

{

$this->debug('这是stream_select检测之前的$read');

$this->debug($this->sockets,true);

$read = $this->sockets;

//校验池子是否有可用的连接

//stream_select返回值不可靠,所以就直接遍历$read

stream_select($read,$w,$e,1);

$this->debug('这是stream_select检测之后的$read');

$this->debug($read,true);

sleep(1);

foreach ($read as $socket)

{

//$socket 可能为 主worker

//也可能是通过stream_socket_accept 创建的连接

if($socket === $this->socket)

{

//创建与客户端连接

$this->createSocket();

}else{

//发送信息

$this->sendMessage($socket);

}

}

}

}

//创建连接

public function createSocket()

{

$client = @stream_socket_accept($this->socket);

//判断是不是闭包

if(is_callable($this->onConnect)){

//执行闭包函数

($this->onConnect)($this,$client);

}

$this->sockets[(int)$client] = $client;

//return $client;

}

public function sendMessage($client)

{

$data = fread($client,65535);

if($data === '' || $data = false)

{

//关闭连接

fclose($client);

unset($this->sockets[(int)$client]);

}

if(is_callable($this->onReceive)){

//执行闭包函数

($this->onReceive)($this,$client,$data);

}

return $data;

}

public function send($conn,$data)

{

$header = "HTTP/1.1 200 OK\r\n";

$header .= "Content-Type:text/html;charset=UTF-8\r\n";

$header .= "Connection:keep-alive\r\n";

$header .= "Content-length:".strlen($data)."\r\n\r\n";

$data =$header.$data;

fwrite($conn,$data);

}

public function debug($data,$flag = false)

{

if($flag){

var_dump($data);

} else {

echo "==== >>>> :".$data."\n";

}

}

//启动服务

public function start()

{

$this->accept();

}

}

Server.php

require __DIR__."/../../vendor/autoload.php";

use zjl\io\Multi\Worker;

 

$host = "tcp://0.0.0.0:9501";

$server = new Worker($host);

 

//连接服务

$server->onConnect = function ($server,$client){

echo "有一个连接进来\n";

var_dump($client);

};

//接收和处理信息

$server->onReceive = function ($server,$client,$data){

echo "给连接发送信息\n";

$server->send($client,"hello world client \n");

};

$server->start();

 

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第7张图片

多路复用IO模型的问题

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第8张图片

yum -y install httpd-tools 安装压力测试工具 ab

ab :是一个轻量级的压力测试工具,模拟多少请求并发

安装方式:yum -y install httpd-tools

-n 请求量 , -c 客户数量 ,-k保持连接

ab -n 10000 -c 1000 -k http://127.0.0.1:9501/

 

ulimit -a

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第9张图片

ulimit -n 202048 设置最大socket连接数

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第10张图片

 

信号函数使用

信号 主要是指linux状态

手机 =》设置闹钟 =》闹钟把你叫醒的这个声音,这个声音就是信号

抗战神剧=》八路军 =》号角 ,号角就是一个信号

linux中,程序执行过程就会有一些信号

程序被kill的信号

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第11张图片

php中处理信号的一个函数 :pcntl_signal ()安装一个信号处理器

【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】_第12张图片

SIGIO:IO处理信号

//安装一个信号

pcntl_signal(SIGIO,"sig_handle");

function sig_handle($sig)

{

sleep(2);

echo "这是测试信号的一个测试类\n";

}

 

//是一个安装信号的操作

//pid => 进程id ,设置信号

//根据进程设置信号

//posix_getpid()获取进程id

posix_kill(posix_getpid(),SIGIO);

 

//如有其他操作,请在分发前操作

echo "其他操作\n";

//分发信号

pcntl_signal_dispatch();

 

信号有很多,如 哨子:集合,命令:向左看向右看,下课铃声。pcntl_signal 就是安装这些信号,表示信号的作用。posix_kill 就是告诉哪些人 这些信号干嘛的 ,pcntl_signal_dispatch就是实战了。

你可能感兴趣的:(【六星教育-swoole-1911 swoole进阶-07非阻塞模型-多路复用模型】)