page contents

swoole 第2次课-走马观花:常用功能快速上手

swoole常用功能快速上手

attachments-2020-11-3B53gAjZ5fb72bc1421be.png

1.阻塞与非阻塞  同步与异步

   同步阻塞顺序执行,异步非阻塞并列执行,

   任务之间依赖就同步阻塞,不依赖就异步非阻塞

2.Swoole常用功能快速上手

   21)http-Server 服务

   用于web项目开发中、对laravel,thinkphp等框架进行加速(框架的条件必须是ioc类型 – 因为swoole是常驻内存)

   案例:用swoole加速laravel框架

    public下的index.php同级下,建立swoole.php文件,进行加速

   <?php

define('LARAVEL_START', microtime(true));

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

//初始化laravel的应用程序
$app = require_once __DIR__.'/../bootstrap/app.php';

//创建laravel的http处理核心对象
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

//高性能HTTP服务器
// 1. 创建swoole的服务
$http = new Swoole\Http\Server("0.0.0.0", 9501);

// 2. 注册事件
$http->on("request", function ($request_swoole, $response_swoole) use ($kernel) { // http 请求事件
//处理laravel接收的请求
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response_swoole->header("Content-Type", "text/plain");
$response_swoole->end(//返回结果
$response->send()
);
//终止中间件
$kernel->terminate($request, $response);

});

// 3. 启动swoole的服务
$http->start();
 运行方法如下
  xshell中关闭防火墙  运行php swoole.php(进入对应目录下)
 浏览器中打开 192.168.204.168:9501( ip:prot)
 看=network中的运行时间
 看xshell窗口中的返回结果
 运行结果,基本正常,速度快了很多

 存在的问题,请求中加不存在的路由,不报错始终在第一页
 解决方法,用加速组件组加速,这里仅是演示,用swoole加速laravel框架

22)WebSocket-Server 服务
      一般用于im通信、任务队列处理之后结果反馈等
      Websocket可以理解为是继承与swoole\server\http 实现的具体细节
      案例: websocket 客户端与服务端建立连接通信
      WebSocket-Server 服务端 websocket.php
      <?php
//创建WebSocket Server对象,监听0.0.0.0:9502端口
$server = new Swoole\Websocket\Server("0.0.0.0", 9502);
//监听WebSocket连接打开事件 当 WebSocket 客户端与服务器建立连接并完成握手后会回调此函数。
$server->on('open', function($server, $req) {
echo "connection open: {$req->fd}\n";
});
//监听WebSocket消息事件 当服务器收到来自客户端的数据帧时会回调此函数
$server->on('message', function($server, $frame) {
echo "received message: {$frame->data}\n";
//向某个客户端(使用 $fd 标识符)发送消息
$server->push($frame->fd, json_encode(["hello", "world"]));
});
/*
message的参数$frame 客户端信息
$frame->fd 客户端的 socket id,使用 $server->push 推送数据时需要用到
$frame->data 数据内容,可以是文本内容也可以是二进制数据,可以通过 opcode 的值来判断。如果是文本类型,编码格式必然是 UTF-8,这是 WebSocket 协议规定的
OpCode 数据类型
WEBSOCKET_OPCODE_TEXT = 0x1 文本数据
WEBSOCKET_OPCODE_BINARY = 0x2 二进制数据
$frame->opcode WebSocket 的 OpCode 类型,可以参考 WebSocket 协议标准文档
$frame->finish 表示数据帧是否完整,一个 WebSocket 请求可能会分成多个数据帧进行发送(底层已经实现了自动合并数据帧,现在不用担心接收到的数据帧不完整)
*/
/*
push方法向 WebSocket 客户端连接推送数据,长度最大不得超过 2M。
参数
int $fd 客户端连接的 ID 发【如果指定的 $fd 对应的 TCP 连接并非 WebSocket 客户端,将会送失败】
string $data 要发送的数据内容
int $opcode 指定发送数据内容的格式 【默认为文本。发送二进制内容 $opcode 参数需要设置为 WEBSOCKET_OPCODE_BINARY】
默认值:WEBSOCKET_OPCODE_TEXT 其它值:WEBSOCKET_OPCODE_BINARY
bool $finish 是否发送完成 默认值:true
*/
//监听WebSocket连接关闭事件
$server->on('close', function($server, $fd) {
echo "connection close: {$fd}\n";
});

$server->start();
      WebSocket-Server 客户端 websocket.html
  <!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>

</body>
<script>
var websocket = new WebSocket('ws://192.168.204.168:9502');
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
};
</script>

</html>
 运行方法
  xshell中关闭防火墙  运行php swoole.php(进入对应目录下)
 浏览器中打开file:///D:/phpstudy_pro/WWW/swoole_2006/class/02/websocket/websocket.html
 看network中的控制台信息
 看xshell的响应
 
23)tcp-Server 服务
       一般用于多语言的交互、即时聊天、短信发送、rpc通信等。
       另:http与websocket均继承与tcp服务端、也就实现tcp服务端中的方法

       案例: tcp 通信  建立连接
       tcp-Server 服务端-- swoole_tcp_server
       <?php
$server = new Swoole\Server("0.0.0.0", 9503);
//建立连接
$server->on('connect', function ($server, $fd){
echo "connection open: {$fd}\n";
});
//接收从客户端发来的信息
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
//发送信息到客户端
$server->send($fd, "Swoole: {$data}");
$server->close($fd);
});
//关闭连接
$server->on('close', function ($server, $fd) {
echo "connection close: {$fd}\n";
});

$server->start();
       tcp-Server 客户端-- swoole_tcp_client
      <?php
//SWOOLE_SOCK_TCP
$client = new Swoole\Client(SWOOLE_SOCK_TCP);

//连接到远程服务器。
if (!$client->connect('127.0.0.1', 9503, -1)) {
$err=$client->errCode;
//$client->close();
exit("connect failed. Error: {$err}\n");
}
/*
参数
string $host 服务器地址【支持自动异步解析域名,$host 可直接传入域名】
int $port 服务器端口
float $timeout 设置超时时间 值单位:秒【支持浮点型,如 1.5 表示 1s+500ms】 默认值:0.5
int $flag 在 UDP 类型时表示是否启用 udp_connect 设定此选项后将绑定 $host 与 $port,此 UDP 将会丢弃非指定 host/port 的数据包。
TCP 类型,$flag=1 表示设置为非阻塞 socket,之后此 fd 会变成异步 IO,connect 会立即返回。
如果将 $flag 设置为 1,那么在 send/recv 前必须使用 swoole_client_select 来检测是否完成了连接。
返回值 成功返回 true 失败返回 false,请检查 errCode 属性获取失败原因
*/

//send 发送数据到远程服务器,必须在建立连接后,才可向对端发送数据。
$client->send("hello world\n");

//从服务器端接收数据。
echo $client->recv();
/*
Swoole\Client->recv(int $size = 65535, int $flags = 0): string | false
参数
int $size:接收数据的缓存区最大长度【此参数不要设置过大,否则会占用较大内存】
int $flags:可设置额外的参数【如 Client::MSG_WAITALL】
返回值:成功收到数据返回字符串 连接关闭返回空字符串 失败返回 false,并设置 $client->errCode 属性
EOF/Length 协议 客户端启用了 EOF/Length 检测后,无需设置 $size 和 $waitall 参数。
* */
//关闭连接。
$client->close();

       运行方法:打开两个xshell ,都关闭防火抢 systemctl stop firewalld,都进入对应目录下
       第一个: php swoole_tcp_server
       第二个: swoole_tcp_client.php
       看两个的响应结果
       
       再看第一个的xschell 的响应结果

       案例2: laravel框架中应用tcp
        tcp-Server 服务端,参见上面的 swoole_tcp_server
       客户端:class\02\frame\laravel6\routes\web.php路由文件中建立个tcp路由
       <?php
Route::get('/tcp', function () {
$client = new Swoole\Client(SWOOLE_SOCK_TCP);

if (!$client->connect('127.0.0.1', 9503, -1)) {
$err=$client->errCode;
//$client->close();
exit("connect failed. Error: {$err}\n");
}
$client->send("hello world\n");

$return = $client->recv();

$client->close();

return $return;
});
      运行方法:打开xshell ,关闭防火墙 systemctl stop firewalld,进入对应目录下,运行 php swoole_tcp_server
      运行结果:
      attachments-2020-11-a4FXS9FF5fb892dc07e87.png
   
24)udp-server 服务
      udp相对来说没有那么可靠信息可能会丢失但速度快
      一般用于直播、群发、广播通知等
      案例: udp的连接
      udp-server 服务端
      <?php
$server = new Swoole\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
/*
SWOOLE_SOCK_UDP 标识为udp,缺省默认为 tcp
UDP 服务器与 TCP 服务器不同,UDP 没有连接的概念。
启动 Server 后,客户端无需 Connect,直接可以向 Server 监听的 9502 端口发送数据包。对应的事件为 onPacket。
*/
//监听数据接收事件
$server->on('Packet', function ($server, $data, $clientInfo) {
$server->sendTo($clientInfo['address'], $clientInfo['port'], "Server ".$data);
var_dump($clientInfo);
});
/*
onPacket接收到 UDP 数据包时回调此函数,发生在 worker 进程中。
function onPacket(Swoole\Server $server, string $data, array $clientInfo);
参数
Swoole\Server $server Swoole\Server 对象
string $data 收到的数据内容,可能是文本或者二进制内容
array $clientInfo 客户端信息包括 address/port/server_socket 等多项客户端信息数据数组
注意
服务器同时监听 TCP/UDP 端口时,收到 TCP 协议的数据会回调 onReceive,收到 UDP 数据包回调 onPacket。
*/
/*
sendto() :向任意的客户端 IP:PORT 发送 UDP 数据包。
Swoole\Server->sendto(string $ip, int $port, string $data, int $serverSocket = -1): bool
参数
string $ip 指定客户端 ip ,$ip 为 IPv4 或 IPv6 字符串,如 192.168.1.102。如果 IP 不合法会返回错误
int $port 指定客户端 port,$port 为 1-65535 的网络端口号,如果端口错误发送会失败
string $data:要发送的数据内容,可以是文本或者二进制内容
int $serverSocket:指定使用哪个端口发送数据包的对应端口 server_socket 描述符【可以在 onPacket 事件的 $clientInfo 中获取】
服务器可能会同时监听多个 UDP 端口,参考多端口监听,此参数可以指定使用哪个端口发送数据包

注意 必须监听了 UDP 的端口,才可以使用向 IPv4 地址发送数据;必须监听了 UDP6 的端口,才可以使用向 IPv6 地址发送数据
*/
$server->start();
       udp-client客户端
       <?php
//SWOOLE_SOCK_TCP
$client = new Swoole\Client(SWOOLE_SOCK_UDP);

//连接到远程服务器。
if (!$client->connect('127.0.0.1', 9502, -1)) {
$err=$client->errCode;
//$client->close();
exit("connect failed. Error: {$err}\n");
}
/*
参数
string $host 服务器地址【支持自动异步解析域名,$host 可直接传入域名】
int $port 服务器端口
float $timeout 设置超时时间 值单位:秒【支持浮点型,如 1.5 表示 1s+500ms】 默认值:0.5
int $flag 在 UDP 类型时表示是否启用 udp_connect 设定此选项后将绑定 $host 与 $port,此 UDP 将会丢弃非指定 host/port 的数据包。
TCP 类型,$flag=1 表示设置为非阻塞 socket,之后此 fd 会变成异步 IO,connect 会立即返回。
如果将 $flag 设置为 1,那么在 send/recv 前必须使用 swoole_client_select 来检测是否完成了连接。
返回值 成功返回 true 失败返回 false,请检查 errCode 属性获取失败原因
*/

//send 发送数据到远程服务器,必须在建立连接后,才可向对端发送数据。
$client->send("hello world\n");

//从服务器端接收数据。
echo $client->recv();
/*
Swoole\Client->recv(int $size = 65535, int $flags = 0): string | false
参数
int $size:接收数据的缓存区最大长度【此参数不要设置过大,否则会占用较大内存】
int $flags:可设置额外的参数【如 Client::MSG_WAITALL】
返回值:成功收到数据返回字符串 连接关闭返回空字符串 失败返回 false,并设置 $client->errCode 属性
EOF/Length 协议 客户端启用了 EOF/Length 检测后,无需设置 $size 和 $waitall 参数。
* */
//关闭连接。
$client->close();
      运行方法:打开两个xshell ,都关闭防火抢 systemctl stop firewalld,都进入对应目录下
       第一个: php swoole_udp_server.php
       第二个: php swoole_udp_client.php
       运行结果
       attachments-2020-11-tEN8qDbz5fb8896210ded.png


3. 定时器

    <?php


//每隔2000ms触发一次
$tick=swoole_timer_tick(2000, function ($timer_id) {
echo "tick-2000ms\n";
});
echo "*****{$tick}*****\n";
$after=swoole_timer_after(3000, function () {
echo "after 3000ms.\n";
});
echo "*****{$after}*****\n";

     打开xshell并进入对应目录下:运行php timer.php

      attachments-2020-11-yyLSz5O65fb89b06f3a42.png

4.网络协议分层结构及完整数据体执行流程

  attachments-2020-11-h5pwLD7P5fbafa11ec8b0.pngattachments-2020-11-Zt4waNxa5fb8d067ebdca.png


实体层:利用光缆、电缆、双绞线、无线电波等方式,把比特位转换位电信号(数据包)。

链接层:匹配数据包中的 mac,实现了点对点的数据通信。

网络层:根据数据包的ip,进行ip的检验与处理,判断是转发还是给自己,即寻找目标主机;

传输层:根据header中的port及协议等数据,使用端口号将网络层主机对主机的通信转换成进程对进程的通信;

应用层:收发传输层的数据,并进行解析。

补充抽象层:Socket是用于给程序与程序之间通信的一个中间层,可以理解为是一个文本资源,程序会对socket进行读写操作而交互的程序或者系统内核也会监听socket的信息变化而执行相应的信息传输
attachments-2020-11-9x5TiyBr5fb9a9cfd3300.png

大体流程: 

 实体层域名请求时,经过路由广播,根据请求时携带数据(header+data)中header中的mac,在链接层中进行匹配,实现了点对点的数据通信;

 再根据header中的ip数据,在网络层中进行ip的检验与处理,判断是转发还是给自己,即寻找目标主机;

 然后根据header中的port及协议等数据,在传输层中,使用端口号将网络层主机对主机的通信转换成进程对进程的通信;

 最后,在应用层中收发传输层的数据,并进行解析。


5.程序-CPU-进程

   一个程序,在一启动时,根据cpu核数,同时开启核数个进程,抢占 cpu资源,保证该程序能抢占到执行权,且同一个程序的进程不会冲突。一旦一个进程抢到了,同一个程序的其他进行,及其他程序的所有进程,都处于等待状态。

  程序间的切换(实质是进程之间的切换),是非常快的,快到你根本感觉不到。举例,如果异步是以s为单位的,程序的切换(串联式的),就是以ns为单位的。

 进程对cpu的关系,就是一个字抢,程序对cpu的关系,分cpu核数个进程,一起抢,最大的保证自己优先执行。

 进程查看:linux是 ps -aux

 程序与进程的关系及进行与进程的关系,同一个程序,会有cpu个进程。同一个程序的进程,进程与进程之间,为父子关系。子进程是由父进程创建出来的,如果子进程脱离父进程则成为孤儿进程。

 父子进行查看命令  Linux命令: pstree -a

 案例 php中创建进程并查看
 <?php
//开始创建子进程
$son_pid = pcntl_fork();//返回子进程的id
/*
* pcntl_fork:pcntl_fork — 在当前进程当前位置产生分支(子进程)
* 返回值
成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。
失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。
* */

//查看当前进程
echo '创建子进程之后当前的进程为:'.posix_getpid().PHP_EOL;
/*
* posix_getpid:以int形式返回当前进程标识符
* PHP 中换行可以用 PHP_EOL 来替代,以提高代码的源代码级可移植性:
* unix系列用 \n
* windows系列用 \r\n
* mac用 \r
* */

//创建了子进程之后
if($son_pid > 0){
echo '子进程id:'.$son_pid.PHP_EOL;
}

//这个循环不能省 处于等待状态,直到手动结束
while (true) {}
   运行方法
   开两个 xshell ,并进入对应目录下
   attachments-2020-11-x5GbFgKa5fba45a26078c.png

 注意,之前在要配置文件 php.ini中,禁用函数中disable_functions 中去除pctnl_fork函数,或着直接注释掉该禁用函数;disable_functions.

6.swoole结构运行

  61)swoole结构运行图

attachments-2020-11-M8cAI58Z5fba5138bff37.png

62)结构介绍

master:主进程。用于处理swoole的核心事件驱动的

Manger:管理进程。对于worker、task进程的创建、回收等操作进行管理。

worker:工作进程。属于swoole的主逻辑进程,用户处理客户端的一系列请求

task:异步任务工作进程

63)swoole官方结构图

     attachments-2020-11-GcRHwtLP5fba52877009e.png


attachments-2020-11-13W1Z9645fba529223e6e.png

64) swoole启动流程
attachments-2020-11-LPwUEF0w5fba52cf33fb7.png

作业:待更新……



  • 发表于 2020-11-05 20:08
  • 阅读 ( 775 )

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
吉洪叶
吉洪叶

21 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1478 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章