TcpClient.GetStream().DataAvailable返回false,但stream有更多数据

Jam*_*mes 10 c# networkstream tcpclient

因此,似乎阻塞的Read()可以在接收到发送给它的所有数据之前返回.反过来,我们用一个循环来包装Read(),该循环由相关流中的DataAvailable值控制.问题是你可以在这个while循环中接收更多数据,但是没有幕后处理让系统知道这一点.我在网上找到的大多数解决方案都不适用于我.

我最后做的是作为循环的最后一步,在从流中读取每个块之后,我做了一个简单的Thread.Sleep(1).这似乎给系统提供了更新的时间,而且我没有得到准确的结果,但这对于解决方案来说似乎有点苛刻且有点"间接".

下面是我正在处理的情况列表:IIS应用程序和独立应用程序之间的单个TCP连接,都是用C#编写的,用于发送/接收通信.它发送请求然后等待响应.此请求由HTTP请求启动,但我没有从HTTP请求中读取数据这个问题,事后是这样.

以下是处理传入连接的基本代码

protected void OnClientCommunication(TcpClient oClient)
{
    NetworkStream stream = oClient.GetStream();
    MemoryStream msIn = new MemoryStream();

    byte[] aMessage = new byte[4096];
    int iBytesRead = 0;

    while ( stream.DataAvailable )
    {
        int iRead = stream.Read(aMessage, 0, aMessage.Length);
        iBytesRead += iRead;
        msIn.Write(aMessage, 0, iRead);
        Thread.Sleep(1);
    }
    MemoryStream msOut = new MemoryStream();

    // .. Do some processing adding data to the msOut stream

    msOut.WriteTo(stream);
    stream.Flush();

    oClient.Close();
}
Run Code Online (Sandbox Code Playgroud)

所有反馈都欢迎提供更好的解决方案,或者只是赞一下需要给Sleep(1)一个允许在检查DataAvailable值之前正确更新的东西.

猜猜我希望2年后这个问题的答案不是如何仍然是:)

Bee*_*Guy 9

我看到了这个问题.
你期望通信会比while()循环更快,这是不太可能的.
while()循环将尽快有没有更多的数据,这可能不是退出几毫秒刚过的情况下完成.

你期待一定数量的字节吗?
怎么经常被OnClientCommunication()解雇?是谁触发了它?

while()循环后你如何处理数据?你是否继续追加以前的数据?

DataAvailable 返回false,因为您的读取速度比通信速度快,所以只有当您不断回到此代码块以处理更多数据时才会返回.


Lar*_*rry 8

您必须知道需要读取多少数据; 你不能简单地循环读取数据,直到没有更多的数据,因为你永远不能确定不会有更多的数据.

这就是HTTP GET结果在HTTP标头中有字节数的原因:因此客户端将知道它何时收到了所有数据.

以下是两种解决方案,具体取决于您是否可以控制另一方发送的内容:

  1. 使用"成帧"字符:(SB)数据(EB),其中SB和EB是起始块和结束块字符(您选择的)但不能在数据内部出现.当你"看到"EB时,你知道你已经完成了.

  2. 在每条消息前面实现一个长度字段,以指示后面有多少数据:(len)数据.读(len),然后读(len)字节; 必要时重复.

这与读取零长度读取意味着数据结束的文件不同(这意味着另一方已断开连接,但这是另一个故事).

第三种(不推荐)解决方案是您可以实现计时器. 一旦开始获取数据,请设置计时器.如果接收循环空闲一段时间(比如几秒钟,如果数据不常出现),您可能会假设没有更多的数据即将到来.最后一种方法是最后的手段......它不是很可靠,很难调整,而且很脆弱.