3

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

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

阅读这样的消息,我想要类似的内容:

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

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

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

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

编辑

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

4

6 回答 6

5

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

我相信它BinaryReader.Read会一直循环下去,直到它被读取到你要求的那么多或者到达流的末尾,但是假设你想在到达流的末尾时抛出异常,我会亲自写一个单独的方法。毕竟,它很容易在一个地方实现并重用。

于 2011-07-22T16:50:07.627 回答
0

Socket.Available如果您不介意等待的紧密循环,会成功吗?

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

于 2011-07-22T16:44:24.943 回答
0

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

于 2011-07-22T16:45:05.420 回答
0

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

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

我要确保实现的一件事是超时机制,以避免在网络出现故障时卡住。

于 2011-07-22T16:59:06.903 回答
0

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

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

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

于 2011-07-22T17:24:16.653 回答
-1

好吧,有点臭,我们必须写一个循环,但我还是希望有人在这个论坛帖子中放一个循环,这样我就可以快速剪切和粘贴它......这是我的(是的,我想要的东西相当及时,但它仅用于单元测试,它们控制模拟服务器,所以我不太在意+我不希望我的单元测试在调用我的 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);
        }
于 2011-12-15T18:40:58.430 回答