我正在编写一个对某些网络设备的状态信息感兴趣的应用程序。其中一个设备通过Http提供状态信息并使用多部分消息;第一次查询信息时,它会向下发送整个状态,然后每当设备状态发生变化时,只会根据更改向流发送新的多部分消息。
我正在使用C#,并且有兴趣使用HttpClient或等价物来打开流,读取当前流中的所有信息,然后监视此流以获取新信息,以便我可以更新设备的状态信息因此在申请中。
本质上我的代码看起来像这样
using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(username, password) })
{
using (var client = new HttpClient(handler))
{
var task = client.GetStreamAsync(uri);
task.Wait();
var stream = task.Result;
while(true)
{
byte[] bytes = ReadBytesFromStream(stream);
DoSomethingWithBytes(bytes);
}
}
现实生活中的代码在一个线程中运行,并且在被告知时需要正确终止。
我遇到的问题是当流中没有任何内容时,对stream.ReadByte()的读取调用会阻塞。如果我在流上放置了ReadTimeout,那么当Read调用失败时(即没有准备好新信息时),CanRead属性设置为false,我必须重新启动该过程,但这样做会再次收到所有原始状态信息只有已经改变的元素。
是否可以做一些事情来保持流存活,直到我告诉它终止,同时如果没有可用的信息,能够解除阻塞?我需要这样做的原因是因为应用程序是多线程的,我需要安全地终止此代码,并且读取会阻止应用程序关闭。
答案 0 :(得分:2)
我没有使用HttpClient
,而是使用HttpWebRequest
并将KeepAlive
设置为true和AllowReadStreamBuffering
属性为true。这样可以使流保持活动状态,并允许您在字节可用时读取字节。
通过保留对从GetResponseStream
返回的网络流的引用,我们可以在NetworkStream上调用Dispose
,它会中断当前正在进行的任何读取,否则只要需要,读取就可以阻塞即直到它收到解决线程生命周期问题的数据。
答案 1 :(得分:0)
处理“I / O操作阻塞我的线程”问题的正确方法是使用异步I / O. .NET网络组件在这里提供了许多选项,但在您的情况下,您似乎正在从流中读取甚至使用(错误地)GetStreamAsync()
方法,因此可以清除代码以正确和干净地处理
例如:
async Task ExecuteUriAsync(string username, string password, Uri uri)
{
using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(username, password) })
{
using (var client = new HttpClient(handler))
{
Stream stream = await client.GetStreamAsync(uri);
byte[] buffer = new byte[10240];
while(true)
{
int byteCount = await stream.ReadAsync(buffer, 0, buffer.Length);
if (byteCount == 0)
{
// end-of-stream...must be done with the connection
return;
}
DoSomethingWithBytes(bytes, byteCount);
}
}
}
}
您的帖子对您之前的ReadBytesFromStream()
方法做了什么以及DoSomethingWithBytes()
做了什么都很模糊,但可能您可以弄清楚如何在上面集成该逻辑。