2.12长轮询 Long Polling

长轮询(Long Polling)是一种实现服务器向客户端推送数据的技术。它通过保持 HTTP 连接打开直到有新数据发送给客户端,或者直到超时为止,从而模拟了服务器推送的效果。长轮询是传统轮询(即客户端定期向服务器发送请求以检查是否有新的数据)的一种改进,可以减少不必要的请求,提高效率。

长轮询(Long Polling)是一种实现服务器向客户端推送数据的技术。它通过保持 HTTP 连接打开直到有新数据发送给客户端,或者直到超时为止,从而模拟了服务器推送的效果。长轮询是传统轮询(即客户端定期向服务器发送请求以检查是否有新的数据)的一种改进,可以减少不必要的请求,提高效率。

长轮询的工作原理:

  1. 客户端向服务器发起一个请求。
  2. 如果服务器上没有新数据,服务器不会立即响应这个请求,而是将请求挂起。
  3. 一旦服务器上有新数据可供发送,或达到了预设的超时时间,服务器就会响应请求,并发送数据给客户端。
  4. 客户端处理完数据后,再次向服务器发起一个新的请求,重复上述过程。

长轮询的应用场景:

  • 实时通知:例如,在线聊天应用中,当用户收到新消息时,服务器可以通过长轮询及时推送消息给客户端。
  • 在线协作工具:如多人同时编辑文档的应用,长轮询可以用来实时同步用户的编辑操作。
  • 游戏更新:在网络游戏中,长轮询可用于实时更新游戏状态,比如玩家位置、得分等信息。
  • 股票市场更新:金融应用程序中使用长轮询来实时显示股票价格变动。
  • 配置中心:在微服务架构中,配置中心使用长轮询技术来确保各个服务能够即时接收到最新的配置变更。当配置发生更改时,配置中心可以迅速将更新推送到所有相关的服务实例,确保配置的一致性和时效性。

以下示例展示了如何使用长轮询请求:

cs
await httpRemoteService.LongPollingAsync("https://localhost:7044/HttpRemote/LongPolling"    , async (responseMessage, token) =>    {        Console.WriteLine(await responseMessage.Content.ReadAsStringAsync(token));        await Task.CompletedTask;    }, cancellationToken: cancellationToken);// 使用构建器模式await httpRemoteService.SendAsync(HttpRequestBuilder    .LongPolling("https://localhost:7044/HttpRemote/LongPolling"    , async (responseMessage, token) =>    {        Console.WriteLine(await responseMessage.Content.ReadAsStringAsync(token));        await Task.CompletedTask;    }), cancellationToken: cancellationToken);

长轮询也支持以 IAsyncEnumerable<HttpResponseMessage> 的方式消费数据,让你可以使用 await foreach 来迭代每个轮询响应:

cs
await foreach (var responseMessage in httpRemoteService.LongPollingAsAsyncEnumerable("https://localhost:7044/HttpRemote/LongPolling", cancellationToken: cancellationToken)){    // 注意:每个响应在使用后需要手动释放(或使用 using)    using (responseMessage)    {        Console.WriteLine(await responseMessage.Content.ReadAsStringAsync(cancellationToken));    }}// 使用构建器模式await foreach (var responseMessage in httpRemoteService.SendAsAsyncEnumerable(HttpRequestBuilder.LongPolling("https://localhost:7044/HttpRemote/LongPolling"), cancellationToken)){    using (responseMessage)    {        Console.WriteLine(await responseMessage.Content.ReadAsStringAsync(cancellationToken));    }}

虽然长轮询在一定程度上解决了实时通信的需求,但它也有一些缺点,比如在高并发情况下可能会对服务器造成较大压力,以及长时间的连接可能会影响服务器的性能。随着 Web 技术的发展,Server-Sent EventsWebSocket 等更先进的技术逐渐成为实现实时双向通信的首选方案。然而,在某些受限环境中,长轮询仍然是一个可行的选择。