1. stream-socket
简单体验 与
socket
连接处理的阻塞状态
函数
| 作用 | 参考地址 |
stream_socket_server
|
创建一个socket
|
https://www.php.net/manual/zh/function.stream-socket-server.php
|
stream_socket_accept
|
用于接收连接
|
https://www.php.net/manual/zh/function.stream-socket-accept.php
|
fread
|
函数读取文件
|
https://www.w3school.com.cn/php/func_filesystem_fread.asp
|
is_callable
|
检测是否存在可运行的函数
|
https://www.php.net/manual/zh/function.is-callable.php
|
call_user_func
|
调用某一个方法
|
https://www.php.net/manual/zh/function.call-user-func.php
|
实例代码:
// 06/stream_socket_server.php
<?php
$host = "tcp://0.0.0.0:9000";
// 创建socket服务
$server = stream_socket_server($host);
echo $host."\n";
// 建立与客户端的连接
// 服务就处于一个挂起的状态 -》 等待连接进来并且呢创建连接
// stream_socket_accept 是阻塞
// 监听连接 -》 可以重复监听
while (true) {
$client = @stream_socket_accept($server);
// sleep(3);
var_dump(fread($client, 65535));
fwrite($client, "server hellow");
fclose($client); var_dump($client);
}
?>
// 06/stream_socket_client.php
<?php
// 是建立连接
$client = stream_socket_client("tcp://127.0.0.1:9000");
$new = time();
// 给socket通写信息
fwrite($client, "hello world");
// 读取信息
var_dump(fread($client, 65535));
// 关闭连接
fclose($client);
echo "\n".time()- $new;
?>
2. 5
大
io
模型
1.1.
阻塞式
I/O
模型
(blocking i/o)
简介
在阻塞式
I/O
模型中,应用程序在从调用
recvfrom
开始到它返回有数据报准备好这段时间是阻塞的,
recvfrom
返回成功后,应用进程开始处理数据报
比喻
-
个人在钓鱼,当没鱼上钩时,就坐在岸边
- -
直等
1.2.
非阻塞式
I/O
模型
(non-blocking i/o)

简介
在非阻塞式
I/O
模型中,应用程序把一个套接口设置为非阻塞就是告诉内核,当所请求的
I/O
操作 无法完成时,不要将进程睡眠,而是返回
-
一个错误,应用程序基于
I/O
操作函数将不断的轮询数据 是否已经准备好,如
果没有准备好,继续轮询,直到数据准备好为止
比喻
边钓鱼边玩手机,隔会再看看有没有鱼上钩,有的话就迅速拉杆
1.3. I/O
复用模型
(i/o multiplexing)

简介
在
I/O
复用模型中,会用到
select
或
poll
函数或
epoll
函数
(Linux2.6
以后的内核开始支持
)
, 这两个函数也会使进程阻塞,但是和阻塞
I/O
所不同的的,这两个函数可以同时阻塞多个
I/O
操作,而且可以同时对多个读操作,多
个写操作的
I/0
函数进行检测,直到有数据可读或可写时,才填正调用
I/O
操作函数
比喻
放了一堆鱼竿
,
在岸边
- -
直守着这堆鱼竿,直到有鱼上钩
1.4
信号驱动式
I/O
模型
(signal-driven i/o)

简介
由
POSIX
规范定义,应用程序告知内核启动某个操作,并让内核在整个操作
(
包括将数据从内核拷贝到应用程序的缓冲区
)
完成后通知应用程序。这种模型与信号驱动模型的主要区别在于
:
信号驱动
I/O
是由内核通知应用程
序何时启动一个
I/O
操作, 而异步
I/O
模型是由内核通知应用程序
I/O
操作何时完成
1.5
异步
I/O
模型
(asynchronous i/o)

简介
由
POSIX
规范定义,应用程序告知内核启动某个操作,并让内核在整个操作
(
包括将数据从内核 拷贝到应用程序的缓冲区
)
完成后通知应用程序。这种模型与信号驱动模型的主要区别在于
:
信 号驱动
I/O
是由内核通知应用
程序何时启动一个
I/O
操作, 而异步
I/O
模型是由内核通知应用程序
I/O
操作何时完成
3.
编辑
io
模型准备
为了更好地理解,网络编程, 写出高性能的服务; 那么首先我们需要了解在进程阻塞的网络服务器的实现过程; 这里我们以原生的代码诠释
为了与项目更好的阅读,方便编辑这里使用一下
composer
来加载命名规则及其诠释代码的目录结构
io-
- src
- Blocking
- NonBlocking
- Multiplexing
- SingnalDriven
- Asynchronous
- test
- blocking
- nonBlocking
- multiplexing
- singnal-driven
- asynchronous
- vendor
- composer.json
构建项目:
$
io>composer init
Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (<vendor>/<name>) [shineyork/io]: test/io
Description []:
Author [, n to skip]: shineyork <test@123.com>
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT
Define your dependencies.
Would you like to define your dependencies (require) interactively [yes]?
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package:
{
"name": "test/io",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "test",
"email": "test@123.com"
}
],
"require": {}
}
Do you confirm generation [yes]? yes
然后修一下
composer.json
即可
{
"name": "test/io",
"description": "io",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "test",
"email": "test@123.com"
}
],
"autoload":{
"psr-4":{
"Test\\Io\\" : "./src/"
}
},
"require": {}
}
4.
阻塞
io
模型
// io/src/Blocking/Worker.php
<?php
namespace Test\Io\Blocking;
// 这是等会自个要写的服务
class Worker
{
// 自定义服务的事件注册函数,
// 这三个是闭包函数
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";
}
// ...
// stream_select
public function on()
{
}
// 需要处理事情
public function accept()
{
// 接收连接和处理使用
while (true) {
$client = @stream_socket_accept($this->socket);
// is_callable判断一个参数是不是闭包
if (is_callable($this->onConnect)) {
// 执行函数
($this->onConnect)($this, $client);
}
// tcp 处理 大数据 重复多发几次
// $buffer = "";
// while (!feof($client)) {
// $buffer = $buffer.fread($client, 65535);
// }
$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();
}
}
// io\test\blocking\server.php
<?php
require __DIR__.'/../../vendor/autoload.php';
use Test\Io\Blocking\Worker;
$host = "tcp://0.0.0.0:9000";
$server = new Worker($host);
// $server->onConnect = function($socket, $client){
// echo "有一个连接进来了\n";
// var_dump($client);
// };
// 接收和处理信息
$server->onReceive = function($socket, $client, $data){
echo "给连接发送信息\n";
$socket->send($client, "hello world client \n");
// fwrite($client, "server hellow");
};
$server->start();