为什么流不支持寻址操作?

7

我目前正在使用TCP/IP套件。我正在编写一个程序,用于在发送端加密文件并在接收端解密文件。当我用网络流的长度初始化字节数组时,遇到了这个异常。以下是我的代码:

if (client.Connected)
{
    NetworkStream binarystream = client.GetStream();
    byte[] receivebytes = new byte[binarystream.Length];
    binarystream.Read(receivebytes, 0, receivebytes.Length);
    Stream file = File.OpenWrite(saveFileDialog1.FileName);
    file.Write(receivebytes, 0, receivebytes.Length);
    file.Close();
    binarystream.Close();
}

控制层次结构确保在创建二进制流实例之前,client.GetStream()返回的流已经被使用过。我遇到的异常在包含以下代码行:
byte[] receivebytes = new byte[binarystream.Length];

它说此流不支持寻找操作。这是什么意思?

1
要确定流的长度,您需要能够读取到其末尾(即您需要“寻找”到末尾)。由于这是一个网络流,因此您不能直接这样做,这就是您遇到错误的原因。您需要将字节读入缓冲区中,直到流结束,然后才能知道有效负载的长度。 - Simon MᶜKenzie
1
@SimonMᶜKenzie 你应该把它发布为答案。 - MarcinJuraszek
@Jawad,我在我的答案中添加了一个例子。不需要刷新。 - Simon MᶜKenzie
1
@SimonMᶜKenzie 哦,好的,非常好的帮助,谢谢你。从那时起,我一直在寻找一种从网络流缓冲字节的方法。你让它变得更容易了。 - Jawad
@BartoszKP 收到,先生。我是新手,在理解这些流和 TCP/IP 套件方面遇到了困难。 - Jawad
显示剩余3条评论
2个回答

11

这是一个流的正常状态。你需要将它类比为春天里的小沙漠河流,就像 Stream 传递字节一样滴水不停。你不知道什么时候它会干涸,这需要一个能够准确预测雨停时间的天气预报。

这样的天气预报确实存在。如果它是 MemoryStream 的话,就没有问题了,因为它可以访问 所有 字节,所以它可以可靠地告诉你什么时候它会干涸。或者是 FileStream,现在操作系统的文件系统可以提供预报。文件数据的目录条目记录了文件长度。

对于 TCP 流来说,这变得更加困难了。TCP 协议本身根本不提供这些信息。你只能一直调用套接字的 Read() 方法,当它返回 0 时,你就知道它停止了。

这通常需要在 TCP 上建立协议。非常普遍的 HTTP 协议就是一个很好的例子。它确实为你提供了天气预报,就是 HttpWebRequest.ContentLength。或者你可以自己制定规则,标准技术是先写入4个字节,表示后面有多少数据。但 NetworkStream 并不适用于特定的协议实现,它只对通用的网络流进行建模。你需要自己添加天气预报。


1
我发现你提供的解释非常有趣和有帮助 :) - Jawad
我想知道缓冲区中的字节是否在每次循环迭代时被替换,因为每次迭代中要存储字节的偏移量始终为0。 - Jawad

1
为了确定流的长度,您需要能够读取到其结尾(即Seek到结尾)。由于这是一个网络流,您不能直接这样做,因此您遇到了错误。您需要将字节不断读入缓冲区,直到流结束,然后才能知道有效负载的长度。以下是一个建议:
if (client.Connected)
{
    NetworkStream binarystream = client.GetStream();
    Stream file = File.OpenWrite(saveFileDialog1.FileName);

    byte[] buffer = new byte[10000];
    int bytesRead;
    while (binarystream.DataAvailable)
    {
        bytesRead = binarystream.Read(buffer, 0, buffer.Length);
        file.Write(buffer, 0, bytesRead);
    }

    file.Close();
    binarystream.Close();
}

请注意,我还建议为每个流实例添加using语句,这可以保证在读/写过程中抛出异常时流将被正确关闭。然后,您可以删除对Close的显式调用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接