swoolel代码演示 - IO模式之多路复用

先来看看服务端

<?php
namespace Zhcsam\Io\Multi;

class Worker
{
    // 这三个是闭包函数
    public $onReceive = null;
    public $onConnect = null;
    public $onClose = null;

    // 连接
    public $socket = null;
    protected $sockets = [];

    public function __construct($socket_address)
    {
        $this->socket = stream_socket_server($socket_address);
        //设置成非阻塞
        stream_set_blocking($this->socket, 0);
        //加入池子
        $this->sockets[(int)$this->socket] = $this->socket;
        // echo $socket_address."\n";
        // $this->debug('stream_socket_server($socket_address);');
        // $this->debug($this->socket, true);
    }
    // 需要处理事情
    public function accept()
    {
        // 接收连接和处理使用
        while (true) {
            $read = $this->sockets;
            //查看有多少资源能用,$read 是过滤后可用的资源

            stream_select($read, $w, $e, 1);
            foreach ($read as $socket) {

              if($socket === $this->socket){
                 //如果是当前的资源,就新建
                 $this->debug("new socket");
                 $this->debug($socket, true);
                 $this->createSocket();
              }else{
                 $this->debug("sendMessage");
                 $this->debug($socket, true);
                 $this->sendMessage($socket);
              }
            }
        }
    }
    public function createSocket()
    {
      // 监听的过程是阻塞的
      $client = stream_socket_accept($this->socket);

      // is_callable判断一个参数是不是闭包
      // if (is_callable($this->onConnect)) {
      //     // 执行函数
      //     ($this->onConnect)($this, $client);
      // }
      $this->sockets[(int) $client] = $client;

    }

    public function sendMessage($client)
    {

      $data = fread($client, 65535);
      if ($data === '' || $data == false) {
          // 关闭连接
          fclose($client);
          unset($this->sockets[(int) $client]);
          return null;
      }
      if (is_callable($this->onReceive)) {
          ($this->onReceive)($this, $client, $data);
      }
    }
    public function debug($data, $flag = false)
    {
        if ($flag) {
            var_dump($data);
        } else {
            echo "==== >>>> : ".$data." \n";
        }
    }
    // 发送信息
    public function send($client, $data)
    {
        $response = "HTTP/1.1 200 OK\r\n";
        $response .= "Content-Type: text/html;charset=UTF-8\r\n";
        $response .= "Connection: keep-alive\r\n";
        $response .= "Content-length: ".strlen($data)."\r\n\r\n";
        $response .= $data;
        echo '发送信息中。。。。';
        fwrite($client, $response);
    }


    // 启动服务的
    public function start()
    {
        $this->accept();
    }
}

再来写调用服务端实例

<?php
require __DIR__.'/../../vendor/autoload.php';
use Zhcsam\Io\Multi\Worker;
$host = "tcp://0.0.0.0:9000";
$server = new Worker($host);
$server->onConnect = function($socket, $client){
    echo "有一个连接进来了\n";
};

// 接收和处理信息
$server->onReceive = function($socket, $client, $data){

    echo "给连接发送信息2222\n";
    sleep(3);
    $socket->send($client, "hello world cli8888ent \n");
    // fwrite($client, "server hellow");
};
$server->start();

客户端的代码部分:

<?php
$host ="tcp://0.0.0.0:9000";
$cliect = stream_socket_client($host);

$new =time();
echo "客户端连接中\n";
fwrite($cliect,'客户端发来信息');
var_dump(fread($cliect, 65535));
echo "其它业务\n";
echo "用时".(time()-$new)."\n";

先来运行服务端php server.php 这时进入监听

运行客户端

php click.php 
客户端连接中
string(126) "HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Content-length: 24

hello world cli8888ent 
"
其它业务
用时3

再来看服务端的变化

php server.php 
==== >>>> : new socket 
resource(11) of type (stream)
==== >>>> : sendMessage 
resource(12) of type (stream)
给连接发送信息2222
发送信息中。。。。==== >>>> : sendMessage 
resource(12) of type (stream)

IO多路复用主要有select、poll、epoll三种模式,select/poll相差不大,主要是通过轮询来不断的检测是否有描述符已就绪,select默认情况下支持最多监控1024个描述符,poll则没有这个限制(底层通过链表实现,可动态增加);epoll不是通过轮询,而是通过回调(callback)方式主动通知已有描述符已就绪,相比较select/poll效率有明显提升。

不管哪种模式的IO多路复用,还都是同步IO,比如当监控的所有的描述符都还没有准备就绪,那么该进程还是阻塞在此

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值