6.网络io模型及阻塞模型

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();

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值