轮询(短轮询),长轮询(comet),长连接(SSE),WebSocket

Web即时通讯:

即时通讯技术就是及时的将服务端数据的结果展示在客户端的view层的一种技术。

应用场景:

在不刷新页面的情况下,实时查看投票结果
支付完成后页面根据入库支付结果显示 “支付成功”
商场自拍机器扫码支付后进入自拍的页面
股票应用的价格及时更改
webIM,ChatRoom,等即时通通讯的聊天室应用等等......

即时通讯四种方式:

轮询、长轮询(comet)、长连接(SSE)、WebSocket。
它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、长轮询和长连接;另一种不是在HTTP基础上实现是,即WebSocket。下面分别对其进行简单的介绍。

【1】轮询

解释:前端(客户端)发起定时器的循环请求后台,后台(服务端)接到请求后返回响应信息的一种方式

setInterval(function() {
    $.ajax({
         type: "get",
         url: '接口地址',
         async: true,
         data:{"type":pay_type,"orderid":order_id}
     }).done(function (data) {
       //do something
    })
}, 10000);

适用于:适用于小型应用,或者同时在线人数较少的应用
优点:简单省时,后端程序编写比较容易(几乎不用做什么特殊处理)
缺点:不及时(得看定时器的间隔),消耗大 ( 服务器宽带和资源)

【2】长轮询(comet)

解释:上面轮询每发出一次请求就要新建一个Http请求,长轮询只启动一个HTTP请求,其连接的服务端会挂起此次连接,后端定时器去查询数据库有没有新消息,直到有新消息才返回响应信息,客户端处理完响应信息后再向服务器发送新的Http请求,以此类推。区别于轮询的就是没有新消息就不会发送新的请求
通俗理解就是把前端的定时器转移到了后端,但是能及时拿到结果

image.png

后端代码具体的不做详细介绍原理如下:
后端写sleep(秒)  睡眠挂起请求,就是把前端的定时器移动到了后端,
后端while循环,不停的问数据库有没有结果。
没有进入定时睡眠,有则跳出循环处理逻辑。
    前端核心就是循环调用ajax(递归)
    // 获取最新的投票结果
    function get_vote() {
        axios.request({
            url: '/get_vote',
            method: 'get'
        }).then(function (response) {
            // 判断后端的数据是否为空
            if (response.data != '') {
                // 获取到最新的数据do somethings
            }
            // 获取完数据后,再发送请求,看还有没有新数据生成
            get_vote()
        });
    }

适用于:适用于小型应用,或者同时在线人数较少的应用
优点:可实现实时数据回传,长轮询和轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。
缺点:连接挂起也会导致资源的浪费(服务器压力大,频繁操作询问数据库有没有新结果)

【3】长连接(SSE)

SSE是HTML5新增的功能,SSE(sever-sent events)服务器端推送事件,是指服务器推送数据给客户端,而不是传统的请求响应模式。简单的说,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“信息”。而SSE最大的特点就是可以实现只要服务器端数据有更新,就可以马上发送到客户端。
注:IE不支持

image.png

//php服务端代码无需其他框架和依赖
header('X-Accel-Buffering: no');
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
ob_end_clean();
ob_implicit_flush(1);
$id = 0;
while (1) {
    $id += 1;
    $data = [
        "id" => $id,
        "message" => '现在是北京时间' . date('Y-m-d H:i:s')
    ];
    $str = '';
    $str .= "id: {$id}" . PHP_EOL;
    $str .= "event: message" . PHP_EOL;
    $str .= "retry: 0" . PHP_EOL;
    $str .= "data:" . json_encode($data) . PHP_EOL;
    $str .= PHP_EOL;
    echo $str;
    sleep(3);
}
//node.js服务端代码
res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      "Access-Control-Allow-Origin": "*" //允许跨域
    });
var num =0;
var f = function(){
   if(num===10){
      res.end();
   }else{
    res.write("id: " + num + "\n");
    res.write("data: " + num + "\n\n");
    num++;
   }
   setTimeout(f,1000);
}
f();
//点前端代码进行兼容性检测
if(typeof(EventSource)!=="undefined"){
    var source = new EventSource('/test/接口');  //指定路由发送
    source.onmessage = function(e) {  
        //监听信息的传输
        var data = JSON.parse(e.data),
        origin = e.origin;
        console.log(data);
       //data   服务器端传回的数据
       //origin服务器端URL的域名部分,有protocol,hostname,port
       //lastEventId用来指定当前数据的序号.主要用来断线重连时数据的有效性
    };
    source.onerror = function(e) {
       //当连接发生error时触发
        console.log(e);
    };
    source.onopen = function(e) { 
      //当连接正式建立时触发
      console.log(e);
    };
}else{
    console.log("不支持SSE");
}

优点:SSE和轮询,长轮询相比它不用处理很多请求,不用每次建立新连接,延迟较低;SSE和WebSocket相比,最大的优势是便利,服务端不需要其他的类库,开发难度较低。
缺点:如果客户端有很多,那就要保持很多长连接浏览器一直转圈,这会占用服务器大量内存和连接数

【4】websocket

阮一峰websocket
websocket 最大的特点就是可以双向通信
php需要用到框架workerman

前端代码
    var ws = new WebSocket("wss://www.aaa.com:8282");
    // 服务端主动推送消息时会触发这里的onmessage
    ws.onmessage = function(e){
        // json数据转换成js对象
        var gateway = JSON.parse(e.data);
        console.log(gateway);
        //以下为gatewaywork的方式
        switch(gateway.type){
            // Events.php中返回的init类型的消息,将client_id发给后台进行uid绑定
            case 'connect':
                var data = {
                    "client_id":gateway.client,
                    'number':"BJ_AC_001_2-0"
                };
                $.ajax({
                    type:"POST",
                    url:"https://www.aaa/version_3/init_bind",
                    data:data,
                });
                break;
            case 'bind_ok':
                console.log("链接上");
                break;
            case 'print':
                console.log("有新消息可以打印了");
                break;
            case'ping':
                ws.send(JSON.stringify({
                    'type':'pong'
                }));
            default :
            // alert(e.data);
        }
    };

websocket 最大的特点就是可以双向通信。这里可以使用.
ws.send()方法发送数据, 不过只能发送String和二进制. 这里,我们通常call 数据叫做 Frames. 他是数据发送的最小单元.包含数据的长度和数据内容.
下面就是前端给后台通信的几种常用的发送方式

 socket.send("Hello server!"); 
 socket.send(JSON.stringify({'msg': 'payload'})); 

  var buffer = new ArrayBuffer(128);
  socket.send(buffer); 

  var intview = new Uint32Array(buffer);
  socket.send(intview); 

  var blob = new Blob([buffer]);
  socket.send(blob); 

优点:WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。可以双向通信
缺点:需要前后端全都换上新的协议支持,WebSocket 技术也比较复杂, 成本比较高,后台开发工期大约需要一周

总结:

短轮询: 请求—响应 —-请求—响应 —-请求—响应
长轮询: 请求—保持挂起—有内容或超过时间才响应
长链接(SSE): 请求—连接—服务器端推送
websocket: 请求—连接—互相交互

最后:综合成本和时间简单项目用轮询,复杂的要求性能的用websocket

你可能感兴趣的:(轮询(短轮询),长轮询(comet),长连接(SSE),WebSocket)