1. 同步与异步
https://www.cnblogs.com/orez88/articles/2513460.html
对于程序的执行流程来说,一般是从上而下的方式来执行, 除非遇到流程控制语句会有一些变化, 但是原则上都会遵循这个原则; 对于PHP来说在单线程的模式下那么一个进程在执行PHP代码的时候就会从第一行执 行到最后一行,那么这个过程我们就可以认为这是同步的,如果中间遇到了sleep()就不得不等待一下执行; 这种模式基本上可以满足于很多的应用场景;
但是并不是绝对的比如:像微信 在网站上登入的时候就会发一条信息在自己的微信账号上提醒你登入了 , 再比如一份订单生成了之后对于用户来说并不会立即收到货,而这个发货的过程我们就可以做成异步的任务由 库存模块处理 等等操作;
2. 阻塞与非阻塞
阻塞:意思就是在哪里等待,要等别人执行完成才能往下去执行;
非阻塞:就是程序可以不用等待执行的结果, 就可以进行下一步的操作;
3. swoole中的异步回调
在swoole中存在这异步的回调模块-》 http://wiki.swoole.com/wiki/page/p-async.html 不过这个回调模块,在4.3版本中讲所有异步客户端模块已经迁移出去,在ext-async扩展中了,推荐使用的是协程客户端;
当然我们可以去github上下载该扩展进行编译安装 https://github.com/swoole/ext-async, 这里我下载的是zip包
根据手册文档https://wiki.swoole.com/wiki/page/1524.html; 异步客户端
4. 长连接
须知:服务器建立和关闭连接均是会有资源的消耗的
长连接:其实就是一直连接的方式
短连接:主要是建立一次连接,就没有了 如ajax
ajax轮询问题:
链接很多那么服务器就会存在这很大的压力;
创建连接关闭连接会消耗很多不必要的资源;
服务端也需要主动发送消息给客户端;
5. 心跳检测
生产问题:
断线、链接超时、阻塞等
服务器ip、运行状态固定,而客户端的ip、运行状态不固定
而对于长连接这种断开的问题;主要的点就在于服务端会保存客户端会话的有效性以及平台上监控所有客户端的网络状况;对于这种功能的实现我们可以通过两种方式实现
a. 轮询机制
轮询:概括来说是服务端定时主动的去与要监控状态的客户端(或者叫其他系统)通信,询问当前的某种状态,客户端返回状态信息,客户端没有返回或返回错误、失效信息、则认为客户端已经宕机,然后服务端自己 内部把这个客户端的状态保存下来(宕机或者其他),如果客户端正常,那么返回正常状态,如果客户端宕机或者返回的是定义的失效状态那么当前的客户端状态是能够及时的监控到的,如果客户端宕机之后重启了那 么当服务端定时来轮询的时候,还是可以正常的获取返回信息,把其状态重新更新。
b. 心跳机制
心跳:最终得到的结果是与轮询一样的但是实现的方式有差别,心跳不是服务端主动去发信息检测客户端状态,而是在服务端保存下来所有客户端的状态信息,然后等待客户端定时来访问服务端,更新自己的当前状 态,如果客户端超过指定的时间没有来更新状态,则认为客户端已经宕机或者其状态异常。
心跳机制与轮询的比较,在我们的应用中,采用的是心跳,这样一是避免服务端的压力,二是灵活好控制,我们的外网服务端(服务端)不知道内网服务端(客户端)的地址,虽然有保存客户 端的socket会话,但是客户端宕机会话就失效了。所以只能等着他主动来报告状态。
注意:在客户端向服务端发送的标识我们可以称之为叫心跳包
什么是心跳包呢?
从客户端到服务器这条巨大的链路中会经过无数的路由器,每个路由器都可能会检测多少秒时间内没有数据包,则会自动关闭连接的节能机制。为了让这个可能会出现的节能机制失效,客户端可以设置一个定时器,每隔 固定时间发送一个随机字符一 字节的数据包,这种数据包就是心跳包。
6 swoole中的心跳检测
https://www.jianshu.com/p/69bc9c7fe5f1
在swoole中我们可以通过set的方式来设置参数值;
heartbeat_check_interval 设置服务器定时检测在线列表的时间间隔
heartbeat_idle_time 设置连接最大的空闲时间,如果最后-一个心跳包的时间与当前时间只差超过设定值则
认为连接 失效。
建议heartbeat_idle_time 比heartbeat_check_interval 的值多两倍多,两倍是为了进行容错允许丢包,
多一点儿是考虑到网络延时的情况,这个可以根据实际的业务情况调整容错率。
6.1 代码
SERVER:
<?php
//创建Server对象,监听 127.0.0.1:9501端口
$serv = new Swoole\Server("127.0.0.1", 9501);
$serv->set([
// https://wiki.swoole.com/wiki/page/283.html
// https://wiki.swoole.com/wiki/page/284.html
//心跳检测,每三秒检测一次,10秒没活动就断开
'heartbeat_idle_time'=>10,//连接最大的空闲时间
'heartbeat_check_interval'=>3 //服务器定时检查
]);
//监听连接进入事件
$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: ".$fd."Close.\n" ;
});
echo "启动swoole tcp server 访问地址 127.0.0.1:9501 \n";
//启动服务器
$serv->start();
?>
CLICK:
<?php
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 "Receive: $data";
});
$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);
$r = 0;
while (true) {
sleep(1);
$r++;
echo $r."\n";
}
?>
效果:根据如上的代码来说就是服务端会检测客户端的访问,如果说服务端在10秒内没有收到信息,就断开客
户端的连接
6.2 swoole客户端下的处理
可以看到如上的效果就是服务端,就会通过检测发现用户在10秒内没有收到client的请求的时候就断开了连
接;我们就可以通过让客户端定时的向服务端发送一个心跳包,提醒服务端;双方是建立了连接的关系的 定时
器可以放在服务器中也可以放在客户端中, 在这个案例中的话我们主要是放在客户端中;
https://wiki.swoole.com/wiki/page/480.html
swoole_timer_tick : 每隔固定时间执行某一个方法,会返回定时器id
swoole_timer_after : 在规定的时间后执行,只执行一次,会返回定时器id
swoole_timer_clear :清空定时器,条件是定时器的id
//每隔2000ms触发一次
swoole_timer_tick(4000, function ($timer_id) use ($client) {
echo "请求信息\n"; $client->send('1');
});
7. udp与tcp
首先我们可以先创一个upd的服务端 找到官网: https://wiki.swoole.com/wiki/page/26.html
我们可以看到在官网中是存在这一个问题, 那就是upd与tcp不同,就是upd可以不用客户进行connect,就可以
直接访问服务端的信息;而在服务端中就会存在只有对应接收信息的onPacket方法; 创建upd客户端,对于客户
端的创建方式实际上并不是特别难,与tcp的同步客户端创建有一些类似,只是需要注意传递的常量
https://wiki.swoole.com/wiki/page/26.html
注意如果udp没有执行 $serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data); 也就是向客户端发送消息那么这个时候就会,客户端阻塞