Long-Polling vs WebSockets 如何选择?

嗨,你好啊,我是猿java

Long-Polling(长轮询)和 WebSockets 是客户端和服务器之间实时通信的两种常见方法,这篇文章,我们将探讨这两种技术的区别、各自的架构、优点、缺点以及适用的使用场景。

什么是实时通信?

实时通信指的是服务器能够在信息可用时立即推送给客户端,而无需客户端显式请求。

这与传统的 HTTP请求-响应模型形成对比,在传统模型中,客户端必须始终发起通信,而长轮询和 WebSockets可以克服这种限制。

客户端和服务器之间的实时通信对于聊天应用程序、体育赛事直播、股票行情、在线游戏和协作工具等应用程序至关重要。

长轮询

长轮询是指客户端向服务器发送 HTTP请求,服务器保持该请求直到有新数据可用,一旦服务器有新数据,它会响应客户端,客户端立即发送新请求。这样就创建了一个持续的连接以实现实时更新。

工作原理

  1. 客户端向服务器发送请求。
  2. 服务器不会立即响应,而是保持请求并等待数据可用。
  3. 当数据可用时(或在超时后),服务器响应请求。
  4. 客户端立即发送另一个请求,重新开始该过程。

优点

  1. 简单性:易于使用标准HTTP基础设施实现。
  2. 兼容性:无需额外配置即可与现有防火墙和代理服务器配合工作。
  3. 备选方案:可以作为不支持 WebSockets的环境中的备选方案。

缺点

  1. 延迟:由于需要建立新的 HTTP连接,延迟较高。
  2. 开销:频繁的 HTTP请求和响应带来较高的开销。
  3. 可扩展性:由于大量打开的 HTTP连接和服务器资源消耗,难以扩展。

何时使用长轮询?

  1. 当你需要支持不支持 WebSockets的旧浏览器或环境时。
  2. 对于更新不频繁,近实时足够的应用程序。
  3. 使用不支持 WebSockets的现有基础设施时。
  4. 对于简单应用程序,不需要 WebSockets的复杂性。

示例

如下示例代码,用 Java模拟了一个长轮询的方式,当服务器接收到客户端的请求时,服务器会将请求写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@RestController
public class LongPollingController {
// 用于存储消息的队列
private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();

// 模拟一个接收消息的端点
@GetMapping("/receive")
public String receive() throws InterruptedException {
// 如果队列为空,等待新的消息
return messageQueue.take();
}

// 模拟一个发送消息的端点
@GetMapping("/send")
public String send(String message) {
messageQueue.offer(message);
return "Message sent!";
}
}

WebSockets

WebSockets提供了一个全双工通信通道,通过单一的、长时间存在的连接进行通信,一旦建立WebSocket连接,服务器和客户端可以独立和异步地发送消息,使其适用于实时、低延迟的应用程序。

工作原理

  1. 客户端通过称为 WebSocket握手的过程发起 WebSocket连接。
  2. 一旦握手成功,连接从 HTTP升级为 WebSocket。
  3. 客户端和服务器可以随时互相发送消息。
  4. 连接保持打开状态,直到任一方决定关闭它。

优点

  1. 真正的实时:允许真正的实时通信,延迟极低。
  2. 全双工通信:客户端和服务器可以独立发送消息。
  3. 高效:初始握手后,每条消息的开销非常低。
  4. 减少服务器负载:服务器不需要为同一客户端处理和维护多个连接。

缺点

  1. 潜在的支持缺乏:某些旧浏览器不支持(尽管这问题越来越小)。
  2. 代理和防火墙:某些代理和防火墙可能无法正确处理 WebSocket连接。
  3. 有状态:服务器需要维护每个连接的状态,对于大量并发连接可能会占用大量内存。
  4. 复杂性:实现 WebSockets可能比传统 HTTP请求更复杂。

何时使用WebSockets

  1. 对于需要真正实时更新的应用程序(如体育赛事直播、实时协作工具)。
  2. 当需要客户端和服务器之间的双向通信时。
  3. 对于频繁更新的应用程序,最小化延迟至关重要。
  4. 当应用程序有许多并发用户时,带宽和服务器资源的效率优先。

两者对比

长轮询和 WebSockets在现代 Web开发中各有其地位。长轮询通过使用标准HTTP请求模拟实时通信,是较简单应用程序或需要支持旧基础设施的理想选择。

另一方面,WebSockets提供真正的实时双向通信,使其成为需要频繁、低延迟更新的应用程序的理想选择。

在设计系统时,请考虑更新频率、并发用户数量、浏览器支持要求以及实现复杂度等因素。

在某些情况下,你甚至可以考虑同时实现两者,在支持的情况下使用WebSockets,并在需要更广泛兼容性时回退到长轮询。

以下是长轮询(Long-polling)与 WebSockets的详细对比表格:

特性 长轮询(Long-polling) WebSockets
通信模式 半双工(客户端请求,服务器响应) 全双工(客户端和服务器可以独立发送消息)
连接持续时间 短连接(每次请求都会打开和关闭连接) 长连接(连接一旦建立,保持打开状态直到关闭)
延迟 较高(由于需要重复建立HTTP连接) 低(连接建立后消息传递迅速)
实现复杂度 简单(使用标准HTTP协议) 较复杂(需要实现WebSocket协议)
服务器负载 较高(频繁的HTTP请求和响应增加服务器负载) 较低(一次握手后保持长连接,减少开销)
带宽使用 较高(频繁的HTTP头部开销) 较低(连接建立后,消息头部开销小)
兼容性 高(支持所有现代浏览器和大多数旧浏览器) 较低(不支持某些旧浏览器和一些防火墙可能不兼容)
代理和防火墙 兼容性好(使用标准HTTP,通常无需特殊配置) 可能需要配置(某些代理和防火墙可能需要特殊配置以支持WebSocket)
状态管理 无状态(每个请求独立处理) 有状态(服务器需要维护每个连接的状态)
适用场景 适用于更新频率较低,延迟要求不高,或者需要支持旧浏览器的应用程序 适用于需要实时更新、双向通信、低延迟以及高并发的应用程序
典型应用 聊天应用、通知系统、数据轮询 实时游戏、实时协作工具、实时金融数据、在线聊天应用
实现示例 使用HTTP GET请求,服务器端保持请求直到有新数据,然后响应 使用WebSocket协议,客户端和服务器通过握手建立连接,然后进行双向通信
资源消耗 高(每个请求都需要新的连接,增加了网络和服务器资源消耗) 低(一次握手后保持长连接,减少了连接开销)
消息顺序 顺序消息(每个请求独立处理,可能会出现消息顺序问题) 保持顺序(连接保持打开,消息顺序一致)

通过这个表格,可以更直观地了解长轮询和 WebSockets的优缺点及其适用场景,从而更好地选择适合实际需求的实时通信技术。

总结

长轮询(Long-polling)和 WebSockets是实现实时通信的两种主要技术:

  • 长轮询使用标准HTTP协议,简单易实现,但延迟较高、服务器负载较大。
  • WebSockets提供全双工、低延迟的通信,但实现复杂,需特殊配置以支持某些代理和防火墙。
  • 长轮询适用于更新频率较低、延迟要求不高的应用,而WebSockets适用于需要实时更新、低延迟和高并发的应用。

长轮询(Long-polling)和 WebSockets该如何选择,需要根据具体需求和环境进行权衡。

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。

drawing