前言
在本次课程开始之前,我们有几个知识点疑问?什么是同步和异步?什么是阻塞和非阻塞?什么是同步阻塞?什么是同步非阻塞?什么是异步阻塞和异步非阻塞?swoole的异步模块和异步客户端;网络通信协议是什么?什么是长连接?为什么需要长连接?swoole怎么做实现长连接?
课程内容
- 同步与异步
- 阻塞与非阻塞
- swoole中的异步回调
- 长连接
- 心跳检测
- swoole中的心跳检测
- swoole客户端下的处理
- udp与tcp
异步与同步
所谓同步,简单来说就是一个人一条龙走到底,PHP运行代码,从上而下。
异步:当一个需要执行很久的任务或代码(耗时任务),我们开另外一个进程,这个进程不需要效率的执行完这个耗时任务,我们称为异步。
异步是相对来说的
阻塞与非阻塞
阻塞:需要等待上一行代码执行完
非阻塞:就是程序可以不用等待执行的结果, 就可以进行下一步的操作
这都是相对的一个过程。
swoole中的异步回调
ps -aux | grep 进程名 查找开启的进程服务,(进程名 是根据运行的文件名来命名的)
下载安装对应版本的异步扩展
php --ri swoole 查看swoole版本
下载对应的版本,不对应的版本,安装不成功
下载好了进行编译安装,这里不做详细操作,详细操作间宝塔安装环境那一节,步骤都一样
安装好之后,需要重启php-fpm服务
find / -name php-fpm* 查找php-fpm位置
/etc/rc.d/init.d/php-fpm-73 restart 重启php-fpm服务
例子测试,根据手册里的例子即可。
swoole同步客户端 是通过生成的客户端对象 直接通过send方法发送数据的,是没有通过事件的。
swoole异步客户端 是通过receive等事件来监听,实现数据的发送和接收,与服务端进行通信。
异步客户端有一个特点:会一直来监听 ,这是一个事件,不会像同步客户端一样请求一次就会断开连接,异步客户端会一直连接,一直监听,会一直接收数据,若在里面发送数据,会一直发送数据,一直接收数据。
同步客户端 是tcp短连接
异步客户端 类似于长连接
TCP服务
//1.创建swoole 默认创建的是一个同步阻塞tcp服务
$host = '127.0.0.1';// 0.0.0.0 代表监听所有
//创建Server对象,监听 127.0.0.1:9501端口
//默认tcp
$serv = new Swoole\Server("127.0.0.1", 9501);
//2.注册事件
$serv->on('Start',function ($serv) use($host){
echo "启动swoole 监听的信息tcp:$host:9501\n";
});
//监听连接进入事件
$serv->on('Connect', function ($serv, $fd) {
echo "Client: $fd Connect.\n";
});
//监听数据接收事件
$serv->on('Receive', function ($serv, $fd, $from_id, $data) {
$serv->send($fd, "Server: ".$data);
});
//监听连接关闭事件
$serv->on('Close', function ($serv, $fd) {
echo "Client: Close.\n";
});
//启动服务器
$serv->start();
同步客户端
$client = new swoole_client(SWOOLE_SOCK_TCP);
//连接到服务器
if (!$client->connect('127.0.0.1', 9501, 0.5))
{
die("connect failed.");
}
function order(){
sleep(4);//某一些的操作造成的时间很长
return "order\n";
}
//向服务器发送数据
if (!$client->send(order()))
{
die("send failed.");
}
//从服务器接收数据
$data = $client->recv();
if (!$data)
{
die("recv failed.");
}
echo $data."\n";
//关闭连接
$client->close();
//另一个事情
//返回结果给用户
echo "订单生成成功\n";
异步客户端
use Swoole\Async\Client;
//异步客户端
$client = new Client(SWOOLE_SOCK_TCP);
$client->on("connect", function(Client $cli) {
$cli->send("GET / HTTP/1.1\r\n\r\n");
});
$client->on("receive", function(Client $cli, $data){
//同步客户端耗时生成订单的过程,放在这里来处理
echo "去生成订单order\n";
sleep(4);
echo "订单成功\n";
});
$client->on("error", function(Client $cli){
echo "error\n";
});
$client->on("close", function(Client $cli){
echo "Connection close\n";
});
$client->connect('127.0.0.1', 9501);
echo "订单生成成功了\n";
长连接
须知:服务器建立和关闭连接均是会有资源的消耗的
长连接:其实就是一直连接的方式 ,一直连接,一直通信
短连接:主要是建立一次连接,就没有了 ajax,一次请求一次结果
那么我们为什么需要长连接呢?
例子:实现一个聊天室,特点:消息相互传递,频率高
那该怎么实现呢?在没有长连接的情况下,怎么通过短连接实现呢?
ajax的特点 就是主动向服务器发送请求,获取数据之后处理;
那么我们可以利用ajax,通过前台轮询的方式去实现。不管是客户端还是服务端;在用户发送了消息之后就需要能接收到并且又能够接收到服务器发送的消息
但是ajax在实现代码的时候因为它的特点只能是主动请求, 因此如果我们需要用ajax来实现的话那么这个时候就不得不让ajax进行轮询;这个时候会发现,前台不断的通过ajax请求与后台获取数据; 并进行响应和输出;如果说是单台服务器并且只是单个连接, 其实问题不大 ; 但是如果说链接很多那么服务器就会存在这很大的压力; 在这个过程中服务器会不断 的创建连接关闭连接会消耗很多不必要的资源;这个时候短连接就无法满足与我们项目的功能的需要 因此就需要长连接的帮助了;其实还存在一个问题服务端也需要主动发送消息给客户端;
这个时候就需要长连接来解决这个问题。
但是长连接有一个问题,就是 长连接保持连接,可能因为网络原因,导致服务断开,客户端断开,这个时候该怎么办呢?
这个时候就涉及到
心跳机制
轮询机制
心跳检测
轮询机制是什么呢?
轮询机制:服务端 定时主动去监控客户端状态,若 客户端 返回状态信息,则证明客户端还连接着。坏处:服务端压力大
心跳机制:客户端定时请求服务端,发送数据信息;服务端 在一定时间内 判断是否存在 信息,若存在,则证明客户端还连接着。
客户端发送的数据信息,称为 心跳包
由于发送的数据只是证明 客户端还在,那么 心跳包 推荐 足够小 一般是0或1
swoole中的心跳检测
$serv->set([
'heartbeat_idle_time' => 10,
'heartbeat_check_interval' => 3,
]);
表示每3秒遍历一次,一个连接如果10秒内未向服务器发送任何数据,此连接将被强制关闭
heartbeat_idle_time表示连接最大允许空闲的时间
heartbeat_check_interval启用心跳检测,此选项表示每隔多久轮循一次,单位为秒
heartbeat_idle_time未设置时默认为interval的两倍
服务端
//1.创建swoole 默认创建的是一个同步阻塞tcp服务
$host = '127.0.0.1';// 0.0.0.0 代表监听所有
//创建Server对象,监听 127.0.0.1:9501端口
//默认tcp
$serv = new Swoole\Server("127.0.0.1", 9501);
//添加配置
$serv->set([
'heartbeat_idle_time' => 10,
'heartbeat_check_interval' => 3,
]);
//2.注册事件
$serv->on('Start',function ($serv) use($host){
echo "启动swoole 监听的信息tcp:$host:9501\n";
});
//监听连接进入事件
$serv->on('Connect', function ($serv, $fd) {
echo "Client: $fd Connect.\n";
});
//监听数据接收事件
$serv->on('Receive', function ($serv, $fd, $from_id, $data) {
$serv->send($fd, "Server: ".$data);
});
//监听连接关闭事件
$serv->on('Close', function ($serv, $fd) {
echo "Client: Close.\n";
});
//启动服务器
$serv->start();
异步客户端
use Swoole\Async\Client;
$client = new Client(SWOOLE_SOCK_TCP);
$client->on("connect", function(Client $cli) {
$cli->send("GET / HTTP/1.1\r\n\r\n");
});
$client->on("receive", function(Client $cli, $data){
//同步客户端耗时生成订单的过程,放在这里来处理
echo "去生成订单order\n";
sleep(4);
echo "订单成功\n";
});
$client->on("error", function(Client $cli){
echo "error\n";
});
$client->on("close", function(Client $cli){
echo "Connection close\n";
});
$client->connect('127.0.0.1', 9501);
//定时的发送消息到服务端,
swoole_timer_tick(8000,function ($timer_id) use($client){
echo "定时发送信息";
$client->send(1);
});
echo "订单生成成功了\n";
以上都是tcp的实现
udp
udp和tcp是两种协议。
udp服务端
//创建Server对象,监听 127.0.0.1:9502端口,类型为SWOOLE_SOCK_UDP
$serv = new swoole_server("0.0.0.0", 9501, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
//监听数据接收事件
$serv->on('Packet', function ($serv, $data, $clientInfo) {
$serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data);
var_dump($clientInfo);
});
//启动服务器
$serv->start();
udp客户端
$client = new swoole_client(SWOOLE_SOCK_UDP);
$client->sendto('127.0.0.1',9501,'udp');
//接收服务信息
$data = $client->recv();
echo 'oo';
这里看出
udp:不负责任 =》只是发生消息不管其他 =》不可靠
1.是不需要建立连接的
2.通信不需要一直保持
tcp:认真 可靠
1.先判断连接是不是成功的
2.再给你发生消息
3.傻傻的等待回复