[Six Star Education -swoole-1911 swoole -06 Advanced network IO model - blocking model]

Foreword

System to deal with some things, some deal with the selection process, and some thread selection process, as to how selection is based on the platform and programming language to decide. Next we need to understand what is network IO model?

stream_socket_server first experience

QQ and other client-side systems communicate via socket and implemented in linux kernel, how to create a socket that it?

php has two functions can be created socket socket, respectively stream_socket_server () and socket_create (), these two functions are to create a socket, there is little difference is stream_socket_server wrapper function, socket_create is native. The only experience stream_socket_server function.

Next we will use native stream_socket_server this function to create a service (relative to swoole create a service, swoole is packaged), and then to connect and request the service.

Native code that implements early experience:

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

// Create a socket service

$server = stream_socket_server($host);

echo $host."\n";

// establish a connection with the client

// After the open service, the service is in a suspended state, waiting for the connection to come in and create a connection

// stream_socket_accept is blocked

// for a long time to come is not connected, it will report a connection timeout warning abnormalities, can suppress abnormal preceded by @

$client = @stream_socket_accept($server);

var_dump($client);

socket connections blocked state process

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

// Create a socket service

$server = stream_socket_server($host);

echo $host."\n";

// establish a connection with the client

// open after the service, the service is in a suspended state, waiting for the connection to come in and create a connection

// stream_socket_accept is blocked

// no connections come in a long time, it will report a connection timeout warning abnormalities, can suppress abnormal preceded by @

// listen for connections when a connection comes in, over, and that is achieved by an infinite loop while repeated listens for connections

while(true){

$client = @stream_socket_accept($server);

var_dump($client);

}

After the service is turned on, when a client connects, the server is connected to receive, after the connection and waits for the connection to continue listening; and the client has been waiting for the return information server, the server if the data is not received for a long time, It is broken and reset.

curl: (56) Recv failure: Connection reset by peer

When a plurality of incoming connections, connected behind the front will not receive the information returned from the server is connected to squeeze

 

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

// Create a socket service

$server = stream_socket_server($host);

echo $host."\n";

// establish a connection with the client

// open after the service, the service is in a suspended state, waiting for the connection to come in and create a connection

// stream_socket_accept is blocked

// no connections come in a long time, it will report a connection timeout warning abnormalities, can suppress abnormal preceded by @

// listen for connections when a connection comes in, over, and that is achieved by an infinite loop while repeated listens for connections

while(true){

// establish a connection with the client

$client = @stream_socket_accept($server);

// read the information of the client

$data = @fread($client,1024);

// send a message to the client

@fwrite($client,'abc');

// close the connection

@fclose($client);

var_dump($client);

}

Here is the server reads the client's information and send information to the client

Creating a client:

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

//创建一个客户端的连接,与服务端accept进行信息交互

$client = stream_socket_client($host);

//给socket通道发送信息

fwrite($client,"hello world");

//接收读取socket通道发送来的信息

var_dump(fread($client,65535));

//关闭连接

fclose($client);

在tcp创建连接之后,假设需要做个耗时操作,sleep(3)一下,看看多个客户端同时连接进来会发生什么情况?

服务端:

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

//创建socket服务

$server = stream_socket_server($host);

echo $host."\n";

//建立与客户端的连接

//开启服务之后,服务就处于一个挂起的状态,等待连接进来然后创建连接

//stream_socket_accept是阻塞的

//长时间没有连接进来,就会报出一个连接超时警告异常,可以在前面加@来抑制异常

//监听连接,当一个连接进来之后,就结束了,那通过一个死循环while来实现一直重复监听连接

while(true){

//建立与客户端的连接

$client = @stream_socket_accept($server);

sleep(3);

//读取客户端的信息

$data = @fread($client,1024);

//发送信息给客户端

@fwrite($client,'abc');

//关闭连接

@fclose($client);

var_dump($data);

}

客户端:

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

//创建一个客户端的连接,与服务端accept进行信息交互

$client = stream_socket_client($host);

$time = time();

//给socket通道发送信息

fwrite($client,"hello world");

//接收读取socket通道发送来的信息

var_dump(fread($client,65535));

//关闭连接

fclose($client);

 

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

这个时候发现第2个客户端必须等待第1个客户端完成之后才会连接,这是为什么呢?

这主要是 stream_socket_server是单线程处理连接的,必须等待前面的连接处理之后再处理后面的,这种状态叫做阻塞调用。那如何解决呢?

swoole 通过Reactor模式解决这个问题,php-fpm通过多进程模式解决这个问题,这些模式统称为网络IO模型

网络IO模型就好比 socket连接处理的框架或架构,比如:原生PHP=》laravel,thinkphp,yii。

5大IO模型

IO管理连接模型

内核:可以理解为 帮助我们去处理这份代码,如何去读,写,关闭,输出。

用户空间:可以理解为去告诉内核处理一些事情,代码就在用户空间里写。

5大io模型:

  • 阻塞I/O(blocking IO):用户空间一直等待内核处理完之前未处理完的事情,且在等待时间内不会去做其他的事情。效率是最低的。
  • 非阻塞I/O(noblocking IO):用户空间先检查内核是否有未处理完的事情,若有,就去做其他的事情,且每隔一段时间检查一次内核是否处理完,这种就是轮询的方式。
  • I/O多路复用    (IO multiplexing ):开辟多个内核,用户空间根据哪个内核空闲就将信息发送给该内核去处理。
  • 信号驱动I/O (signal driven IO):用户空间设置一个信息号就会去做其他的事情(对用户空间来说是非阻塞的),内核处理完未处理的事情之后会处理这个事情,处理完这个事情之后会返回该信号,表示处理完这个事情。触发回调函数。
  • 异步I/O (asynchronous IO):预定模式 ,用户空间一般用事件event=》事先今天发送一个信息给内核,并告诉内核在指定的时间节点去处理这件事情,(对于用户空间来说是非阻塞的),触发回调函数。通常事件发送完之后还需要事件清理(原因是内核处理完一件事情后,在下一个时间节点有可能在做其他的事情了)。

 

为什么要理解5大IO模型?对我们来说有什么意义?

通过理解网络编程的一些技术知识,为了更好的理解学习swoole。

 

简单IO架构(代码层面)

应用composer命名空间

io

src

SignalDriven

worker.php

test

signal-driver

server.php

client.php

先创建io目录,打开cmd,cd到io目录下,输入composer init,回车,创建属于自己的命名空间;

配置一下Package name ,Auth,Package Type,License

就会在io目录下生成一个composer.json文件

然后创建一下目录 ,src(存放自己原生写的封装的类),test目录(测试用的目录包)。然后再composer.json文件里配置一下命名空间,添加配置如下:

"autoload":{

"psr-4":{

"zjl\\io\\":"./src/"

}

},

测试一下:

在src目录下创建Index.php,编写测试代码如下:

然后composer update一下

这时候会生成vendor目录及文件

然后在io目录下创建一个test.php。(可以参照workerman的架构)

然后再cmd 上运行一下 php test.php ,这样就可以了。

阻塞IO模型

Worker.php

<?php

namespace zjl\io\Blocking;

 

/**

* 用户连接服务

*/

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

<?php

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

use zjl\io\Blocking\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();

 

测试

php server.php

 

curl http://127.0.0.1:9501

Guess you like

Origin www.cnblogs.com/fish-minuet/p/12108198.html