C# 当NetworkStream.Read(字节[],int,int)需要返回-1时,它将中止()它正在运行的线程?
上述代码设计用于在单独的线程上运行时从C# 当NetworkStream.Read(字节[],int,int)需要返回-1时,它将中止()它正在运行的线程?,c#,networking,stream,C#,Networking,Stream,上述代码设计用于在单独的线程上运行时从TcpClient检索消息Read方法工作正常,直到它应该返回-1以指示不再有任何内容可读取;相反,它只是在没有任何明显原因的情况下终止它正在运行的线程——使用调试器跟踪每个步骤表明它只是在该行之后停止运行 我还尝试用try。。。捕获,但未取得多大成功 这可能是什么原因造成的 编辑:我试过了 NetworkStream stream = socket.GetStream(); if (stream.CanRead)
TcpClient
检索消息Read
方法工作正常,直到它应该返回-1以指示不再有任何内容可读取;相反,它只是在没有任何明显原因的情况下终止它正在运行的线程——使用调试器跟踪每个步骤表明它只是在该行之后停止运行
我还尝试用try。。。捕获
,但未取得多大成功
这可能是什么原因造成的
编辑:我试过了
NetworkStream stream = socket.GetStream();
if (stream.CanRead)
{
while (true)
{
int i = stream.Read(buf, 0, 1024);
result += Encoding.ASCII.GetString(buf, 0, i);
}
}
感谢@JonSkeet,但问题仍然存在。线程终止于read
行
EDIT2:我像这样修改了代码,它成功了
NetworkStream stream = socket.GetStream();
if (stream.CanRead)
{
while (true)
{
int i = stream.Read(buf, 0, 1024);
if (i == 0)
{
break;
}
result += Encoding.ASCII.GetString(buf, 0, i);
}
}
我认为问题很简单,我只是想得不够透彻。谢谢大家看这个 否,当没有可读取内容时返回0,而不是-1:
返回值读入缓冲区的总字节数。如果当前有那么多字节不可用,则该值可以小于请求的字节数;如果已到达流的末尾,则该值可以小于零(0)
我的猜测是,实际上,没有抛出异常,线程也没有被中止——但它只是永远循环。如果在调试器中单步执行,您应该能够看到这一点。无论发生什么情况,您的“愉快”终止条件将永远不会达到…在我看来,它只是在阻塞,即在流的末尾等待。要返回非正数,必须关闭流,即调用方不仅发送了数据,还关闭了出站套接字。否则,系统无法区分“等待数据包到达”和“流结束” 如果呼叫者只发送一条消息,他们应该在发送后关闭出站套接字(他们可以保持入站套接字打开以获得回复)
如果调用方正在发送多条消息,则必须使用帧方法来读取单个子消息。对于基于文本的协议,这通常意味着“搜索换行符”。由于您试图从流中读取ASCII字符,请查看以下可能更简单的方法:
while (stream.DataAvailable)
{
int i = stream.Read(buf, 0, 1024);
result += Encoding.ASCII.GetString(buf, 0, i);
}
public IEnumerable可读行(流)
{
使用(StreamReader=newstreamreader(stream,Encoding.ASCII))
{
而(!reader.EndOfStream)
产生返回reader.ReadLine();
}
}
虽然这可能不是您想要的,但重点是:
- 使用
为您完成所有繁重的工作StreamReader
- 使用带有
在流中循环的while循环!reader.EndOfStream
- 如果希望将块读入缓冲区并附加到结果中,您仍然可以使用
。请注意,这些将是reader.Read(buffer,01024)
块,而不是char[]
块,这可能是您想要的byte[]
DataAvailable
;这并不意味着你认为它会做什么,而且通常会导致数据错误。DataAvailable
的唯一有效用途是决定“我应该以同步还是异步的方式进行下一次读取”之类的事情。它与您的编辑一起工作是偶然的;对于您的场景,这不是一个可靠的解决方案。您可能希望使用我的网络库(),这样您就不必自己编写网络层了。@MarcGravel我明白您的意思了。因此,我在while
循环之前额外添加了两行inti=stream.Read(…)
和result+=…
,以确保流与下一个传入数据包同步。当我100%确定有人正在向我发送数据包时,将调用此方法。@Kenny“packet”不是“send”的同义词;你能得到的可能是:一整条信息;几个完整的消息;半封信;一个字节;一条消息的结尾、整个第二条消息和第三条消息的开头;各种其他的疯狂。说真的,使用DataAvailable,或者从数据包的角度考虑是一个错误。您必须从流的角度思考,并应用“框架”方法。
public IEnumerable<string> ReadLines(Stream stream)
{
using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
{
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
}