【问题标题】:.NET blocking socket read until X bytes are available?.NET 阻塞套接字读取直到 X 字节可用?
【发布时间】:2017-08-26 02:17:59
【问题描述】:

假设我通过 TCP 实现了简单的协议,其中每条消息由以下部分组成:

  1. int 表示数据长度。
  2. 二进制数据,长度在 1 中指定。

读到这样的消息,我想:

int length = input.ReadInt();
byte[] data = input.ReadBytes(length);

使用Socket.ReceiveNetworkStream.Read 读取可用的字节数。我希望阻止对ReadBytes 的调用,直到length 字节可用。

有没有一种简单的方法可以做到这一点,而不必循环读取,在偏移处重新开始等待剩余数据?

在实际应用程序中,读取可能应该在异步或后台线程上完成,但我暂时忽略了这一点。重要的是在所有数据都可用之前能够不完成读取。

编辑

我知道我可以自己缓冲数据,而且我知道该怎么做。它只是围绕Receive 的循环,在下一个偏移量处继续。 我要问的是是否有这样一个循环的可重用实现,而不需要任何类型的自己的循环(或者当所有数据可用时完成的可重用异步实现)。

【问题讨论】:

    标签: c# .net sockets networkstream


    【解决方案1】:

    某事,某处将不得不循环。毕竟,可能需要多次读取套接字。

    我相信BinaryReader.Read 将继续循环,直到它被读取到您要求的数量或到达流的末尾,但假设您希望在到达流的末尾时抛出异常,我会亲自写一个单独的方法。毕竟,它很容易在一个地方实现并重复使用。

    【讨论】:

    • BinaryReader.Read 文档说它返回读取的字节数,并且 如果有那么多字节不可用,这可能小于请求的字节数。我想我必须测试这是否意味着“现在可用的字节”或“在套接字关闭之前收到的字节”。
    • @Anders:是的,文档不清楚。我相信它循环 - 但这种歧义只是编写自己的方法的另一个原因。大约 7 行代码 - 去做吧 :)
    • 太糟糕了,你不在 Java 中,read(new byte[9]) 将阻塞,直到读入 9 个字节......我在同一条船上寻找简单的东西。请注意,我不会在我的模拟服务器中循环。我们只需读取(new byte[1]) 以获取帧大小标头,然后读取(new byte[length]) 以获取数据包本身...没有循环,在我们发送请求后仅读取两次。
    • @DeanHiller:这取决于输入流 - 但一般来说, InputStream.read 将不会 阻塞,直到它填满缓冲区。 DataInputStream.readFully 会,但那是另一回事。如果您在一般的InputStream 上使用读取而不检查返回值,那么您将面临失败。
    • @JonSkeet,对不起,我在想 BufferedInputStream 这是常用的,所以没有开发人员必须编写循环......是的,基本 InputStreams 不这样做......C# 需要那个,会很好。显然你只是用缓冲的包装任何 InputStream 并从 BufferInputStream 读取
    【解决方案2】:

    Socket.Available 可以解决问题,如果您不介意等待的紧密循环?

    http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.available%28VS.71%29.aspx

    【讨论】:

    • 小心 - 如果您不读取数据,它将停止套接字,因此如果您等待的不仅仅是一个微小的数据片段,您可能会永远等待。因此,我不会使用它来等到收到一定数量的数据。
    【解决方案3】:

    数据需要自己缓冲,read的规范是在返回时可以读取1个字节到缓冲区大小之间的任意数量。

    【讨论】:

      【解决方案4】:

      听起来 yield 语句可以很好地适应这种情况。

      即假设有一个循环监视传入的流,一旦你点击每个长度数字,你就会通过 'yield' 将控制权交还给调用者给 IEnumerable / foreach。

      也许收益可以反过来通过事件发出信号,以替代与 IEnumerable 的解耦。不过我觉得 IEnumerable 很方便。

      【讨论】:

        【解决方案5】:

        看看下面的链接: http://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html

        在此链接中,您将找到有关套接字和库的优秀信息。

        我要确保实现的一件事是超时机制,以便 避免网络变坏时卡住。

        【讨论】:

          【解决方案6】:

          好吧,有点臭,我们必须写一个循环,但我还是希望有人在这个论坛帖子中放一个循环,这样我就可以快速剪切和粘贴它......这是我的(是的,我我宁愿以时间为基础,但它仅用于单元测试,它们控制模拟服务器,所以我不太在意+我不希望我的单元测试在调用我的 Read 方法时卡在失败中)

                  int numBytes = 0;
                  int i = 0;
                  while(numBytes != length)
                  {
                      numBytes += latestClient.Receive(body, numBytes, length-numBytes, SocketFlags.None);                
                      if(i == 10000)
                          throw new Exception("Could not read enough data.  read="+numBytes+" but expected="+length);
                  }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-12-27
            • 2012-07-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-28
            • 2013-04-19
            相关资源
            最近更新 更多