简介

轮询、长连接和 WebSocket 都是实现 Web 即时通信的机制。根据基于的协议可以分为两类:基于 HTTP 协议实现和基于 WebSocket 协议实现。
这里主要介绍基于 HTTP 协议的三种方式:短轮询、长轮询和长连接。

短轮询

定义

短轮询就是普通的、常规的轮询:浏览器每隔一段固定的时间就像服务器发送 HTTP 请求,服务器在收到请求后,不管是否有数据需要发送更新,都直接进行响应。

本质上还是浏览器发送请求,服务器接收请求的过程

实现

1
2
3
4
5
6
var xhr = new XMLHttpRequest();
setInterval(function(){
xhr.open('GET','/user');
xhr.onreadystatechange = function(){};
xhr.send();
},1000)

特点

  • 实现简单;
  • 因为需要不断的建立新的 HTTP 连接,非常浪费服务器和客户端的资源;
  • 响应的结果没有顺序并且包含一定的延时;

长轮询:comet

流程

  • 客户端发送 Ajax 请求到服务器,服务器在有消息之前将该请求挂起。
  • 当服务端数据更新或者有消息后,服务器将作出响应。如果一直没有数据更新,则到达一定的时间限制也会做出响应。
  • 客户端处理服务器的响应后,立即发出一个新的请求。
image.png

实现

1
2
3
4
5
6
7
8
function ajax(){
var xhr = new XMLHttpRequest();
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
ajax();
};
xhr.send();
}

特点

优点

  • 和短轮询相比数据未更新时不会频繁的请求,耗费的资源少。

缺点

  • 服务器挂起连接会消耗服务器的资源;
  • 响应数据没有顺序;
  • 在同一时刻,客户端对相同服务器的 HTTP 连接数量有最大限制。最好同一个用户只存在一个长轮询。

长连接:SSE

定义

长连接是 HTTP/1.1 中出现的。它本质上和轮询机制不同,允许多个 HTTP 请求共用一个 TCP 连接。服务器只要数据有更新就可以马上发送到客户端。

SSE:Server-Sent Events
可以减少频繁建立 TCP 连接所带来的资源浪费和时间损耗。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
//需要判断浏览器支不支持,可以去 w3c 进行查看
var source = new EventSource('/get_data');
source.onmessage = function (event) {
console.info(event.data);
document.getElementById('result').innerText = event.data
};

</script>
</head>
<body>
<div id="result"></div>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//produces 必须为"text/event-stream;charset=UTF-8"
@RequestMapping(value = "/get_data", produces = "text/event-stream;charset=UTF-8")
public String getData(){
try {
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}

double moeny=Math.random()*10;
System.out.println(String.format("%.2f",moeny));
DecimalFormat df = new DecimalFormat(".00");
String canshu=df.format(moeny);
//EventSource 返回的参数必须以 data: 开头,"\n\n"结尾,不然 onmessage 方法无法执行。
return "data: 白菜价格行情:" + canshu+"元"+ "\n\n";
}

特点

优点

  • 多个 HTTP 请求共用一个 TCP 连接,不需要建立或保持大量的请求。

缺点

  • 服务器维护一个长连接会增加开销。
  • 浏览器对同一个域有并发数量限制,长连接会持续性的占用浏览器和服务器的一个连接,从而资源无法释放。

    例:Chrome 浏览器对于并发数量的限制为 6

对比 WebSocket 协议

  • SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。
  • SSE 通常只用来传送文本,二进制数据需要编码后传送。WebSocket 默认支持传送二进制数据。
  • SSE 属于轻量级,使用简单。WebSocket 协议相对复杂。
  • SSE 默认支持断线重连。WebSocket 需要自己实现。
  • SSE 支持自定义发送的消息类型。
  • SSE 是 单通道,WebSocket 是双通道。

    单通道:使用 SSE 时,服务端向客户端发消息且占用一个连接。如果客户端要向服务端通信,需额外打开一个连接。

参考

  1. 长轮询(Long polling)
  2. 轮询、长轮询、长连接、websocket
  3. web 通讯的四种方式,短轮询、长轮询 (comet)、长连接 (SSE)、WebSocket
  4. springboot 的服务端推送技术 SSE
  5. 轮询、长轮询 (comet)、长连接 (SSE)、WebSocket–简书