使用 Httpclient 进行长轮询
Posted
技术标签:
【中文标题】使用 Httpclient 进行长轮询【英文标题】:Long polling with Httpclient 【发布时间】:2017-05-15 08:56:59 【问题描述】:我正在使用 .Net HttpClient
使用一个 REST API (GET)。我想用long polling调用这个API。
我有几个问题:
-
使用长轮询检索数据的最佳方法是什么?
这是我的用例 - 我的应用程序将通过长轮询来使用这个 api,并根据结果我将在不同的线程上执行一些操作。基于 long poll get 的新响应,我将中止/完成旧线程并再次在新线程上开始操作。如何使用 Tasks 实现这一点?
【问题讨论】:
【参考方案1】:对于第一个问题,我找到了this 解决方案,效果很好:
var url = "http://your.url";
using (var client = new HttpClient())
client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
var request = new HttpRequestMessage(HttpMethod.Get, url);
using (var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead))
using (var body = await response.Content.ReadAsStreamAsync())
using (var reader = new StreamReader(body))
while (!reader.EndOfStream)
Console.WriteLine(reader.ReadLine());
【讨论】:
【参考方案2】:我目前正在这样做。我有一个作为 Windows 服务运行的客户端。在启动时,服务将向网络服务器发布一个 serviceID 以进行识别。如果没有找到现有的 ID,它基本上只是在启动时生成的 GUID。
注册后,服务将在长轮询 Web 服务器资源上启动长轮询 http 请求。 Web 服务将在设定的时间内停放呼叫者。如果没有从其他服务接收到唤醒呼叫,则客户端请求会得到答复并说明原因。客户端会在处理完响应后立即开始一个新的长轮询请求。
Web 服务还具有用于其他服务的 WakeUp 资源,以指示特定的 serviceID 应该接收实际的 WakeUp。 Longpolling 和 WakeUp 函数共享要唤醒的 serviceID 列表。根据您的目标,您可以有多种唤醒原因,具体取决于您的解决方案的复杂性。
Windows 服务被实现为多线程应用程序。如果服务从服务控制管理器接收到 OnStop 事件,则一个通用控制线程处理通用 Windows 服务管理内容并向工作线程发出信号。它也是设置所有其他事情的线程。实例化其他工作线程并启动它们。
LongPolling 线程,唯一的工作就是处理 longpolling 调用的结果。当收到响应时,它会检查结果并根据结果激活其他线程,然后启动新的长轮询请求。这意味着它能够在其他工作线程正在处理它们的任务时接收新任务。
如上所述,您可以有多个不同的工作线程来做不同的事情。移动文件、安装应用程序、删除非法应用程序、备份文件夹。天空真的是极限。
这几乎是我系统的基本设计,而且效果非常好。它简单易用。
【讨论】:
【参考方案3】:var socketsHandler = new SocketsHttpHandler
PooledConnectionIdleTimeout = TimeSpan.FromHours(27),//Actually 5 mins can be idle at maximum. Note that timeouts longer than the TCP timeout may be ignored if no keep-alive TCP message is set at the transport level.
MaxConnectionsPerServer = 10
;
client = new HttpClient(socketsHandler);
如您所见,虽然我将空闲超时设置为 27 小时,但实际上它只保持 5 分钟。
所以,最后我只是每 1 分钟使用相同的 HttpClient 调用目标端点。在这种情况下,始终存在已建立的连接。您可以使用 netstat 进行检查。
【讨论】:
以上是关于使用 Httpclient 进行长轮询的主要内容,如果未能解决你的问题,请参考以下文章
使用 WinAPI 的 InternetReadFile() 进行长轮询