浅析Web实时通信的方法总结:短轮询/长轮询/SSE/Websocket的介绍及性能和兼容性对比、SSE的工作原理及如何实现
一、Web端即时通讯技术
即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的。
但是在Web中,由于浏览器的限制,实现即时通讯需要借助一些方法。这种限制出现的主要原因是,一般的Web通信都是浏览器先发送请求到服务器,服务器再进行响应完成数据的现实更新。
二、实现Web端即时通讯的方法
实现即时通讯主要有四种方式,它们分别是:短轮询、长轮询(comet)、长连接(SSE)、WebSocket。
它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、comet和SSE;另一种不是在HTTP基础上实现是,即WebSocket。下面分别介绍一下这四种轮询方式,以及它们各自的优缺点。
1、短轮询
短轮询的基本思路就是浏览器每隔一段时间向浏览器发送http请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。
这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。
这种方式的优点是比较简单,易于理解,实现起来也没有什么技术难点。缺点是显而易见的,这种方式由于需要不断的建立http连接,严重浪费了服务器端和客户端的资源。尤其是在客户端,距离来说,如果有数量级想对比较大的人同时位于基于短轮询的应用中,那么每一个用户的客户端都会疯狂的向服务器端发送http请求,而且不会间断。人数越多,服务器端压力越大,这是很不合理的。
因此短轮询不适用于那些同时在线用户数量比较大,并且很注重性能的Web应用。
2、comet -长轮询
comet 指的是,当服务器收到客户端发来的请求后,不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制(服务器端设置)后关闭连接。
长轮询和短轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。
3、SSE
SSE是HTML5新增的功能,全称为Server-SentEvents。它可以允许服务推送数据到客户端。SSE在本质上就与之前的长轮询、短轮询不同,虽然都是基于http协议的,但是轮询需要客户端先发送请求。
而SSE最大的特点就是不需要客户端发送请求,可以实现只要服务器端数据有更新,就可以马上发送到客户端。
SSE的优势很明显,它不需要建立或保持大量的客户端发往服务器端的请求,节约了很多资源,提升应用性能。并且后面会介绍道,SSE的实现非常简单,并且不需要依赖其他插件。
4、WebSocket
WebSocket是HTML5定义的一个新协议,与传统的http协议不同,该协议可以实现服务器与客户端之间全双工通信。
简单来说,首先需要在客户端和服务器端建立起一个连接,这部分需要http。连接一旦建立,客户端和服务器端就处于平等的地位,可以相互发送数据,不存在请求和响应的区别。
WebSocket的优点是实现了双向通信,缺点是服务器端的逻辑非常复杂。现在针对不同的后台语言有不同的插件可以使用。
三、四种Web即时通信技术比较
从兼容性角度考虑,短轮询>长轮询>长连接SSE>WebSocket
从性能方面考虑,WebSocket>长连接SSE>长轮询>短轮询
四、SSE 原理理解及如何实现
1、SSE 原理
SSE不需要依赖客户端向服务器发送请求,而是可以直接在服务器端有数据更新时进行发送到客户端,相比于轮询的“拉数据”,这种“推数据” 有着低延迟、高性能的优势。这种方法的服务器端非常简介,只要维护一个服务器和客户端之间的协议即可,前端使用EventSource对象。
服务器端需要提供的协议基本代码如下:
data:firstevent
data:secondevent
id:100
event:myevent
data:thirdevent
id:101
:thisisacomment
data:fourthevent
data:fourtheventcontinue
下面解释一下基本用法:
要定义各个事件,每一个事件之间使用一个换行符隔开。每个事件内部可以有多行,每一行都是type:value的形式。
type有以下几种选择:
(1)类型为空白,表示该行是注释,会在处理时被忽略。
(2)类型为data,表示该行包含的是数据。以data开头的行可以出现多次。所有这些行都是该事件的数据。
(3)类型为event,表示该行用来声明事件的类型。浏览器在收到数据时,会产生对应类型的事件。
(4)类型为id,表示该行用来声明事件的标识符。
(5)类型为retry,表示该行用来声明浏览器在连接断开之后进行再次连接之前的等待时间。
比如上面的第一个事件,只传输了一个数据,数据内容为firstevent。服务器端通过这个清单发送到客户端,就可以通过前端进行响应的处理,诸如读取新数据、更新界面等。
客户端需要在JavaScript中使用EventSource对象。
首先需要初始化一个EventSource对象,实例化的时候需要传入与其交互的服务器端的文件地址,如:
var es = new EventSource(“sse.php”);
接下来,可以对进行事件的监听。EventSource给出了三种标准事件,它们的名称和触发时机如下:
open 当成功与服务器建立连接时执行
message 当收到服务器发送的事件时执行
error 当出现错误时执行
和普通的事件一样,可以通过以下两种方法使用这些事件:
es.onmessage=function(e){};
es.addEventListener(“message”,function(e){});
2、实现:
服务器端代码(php):
<?php
header('Content-Type: text/event-stream'); //这是专门为sse设置的数据格式
$time = date('Y-m-d H:i:s');
//下面这些echo出来的东西就是上面说的服务器端和客户端之间的协议
echo 'retry: 3000'.PHP_EOL; //retry类型的数据,规定了浏览器在连接断开之后进行再次连接之前的等待时间
echo 'data: The server time is: '.$time.PHP_EOL.PHP_EOL;
?>
//注意必须要先设定content-type为text/event-stream,这是为SSE专门定义的数据传输格式。
//接下来通过php的echo输出协议,上面的代码输出的结果如下:
//retry:3000
//data:Theservertimeis...
//输出了一个事件,这个事件中分别定义了retry类型和data类型的行。
客户端代码:
<html>
<head>
<meta charset="UTF-8">
<title>basic SSE test</title>
</head>
<body>
<div id=”content”></div>
</body>
<script>
var es = new EventSource("sse.php");
es.addEventListener("message",function(e){
document.getElementById("content").innerHTML += "\n"+e.data;
});
</script>
</html>
五、WebSocket 原理
1、原理 —— WebSocket 实现了一次连接,双方通信的功能。
首先由客户端发出WebSocket请求,服务器端进行响应,实现类似TCP握手的动作。这个连接一旦建立起来,就保持在客户端和服务器之间,两者之间可以直接的进行数据的互相传送。服务器端的逻辑比较复杂,如果是java或者node开发,都有很多封装好的组件可以使用。
2、前端API:
(1)创建WebSocket对象
var ws = new WebSocket(“ws//localhost:8080”);
WebSocket是一个不同于HTTP的协议,其参数传递中的ws://前缀类似于http://,用于进行协议的声明。
(2)事件操作 —— WebSocket提供了四个事件操作,如下:
onmessage收到服务器响应时执行
onerroe 出现异常时执行
onopen 建立起连接时执行
onclose 断开连接时执行