【问题标题】:NetworkStream doesn't support seek operationsNetworkStream 不支持查找操作
【发布时间】:2012-07-31 21:08:17
【问题描述】:

我正在创建简单的代理服务器,但遇到了一个奇怪的情况,我有以下代码:

var clientRequestStream = _tcpClient.GetStream();
var requestHeader = clientRequestStream.GetUtf8String();

GetUtf8StringStream 类的扩展方法,它读取流(包含HttpRequest 标头)。我需要提取这些标头以访问 Host 和 Requested Url。一旦读取 NetworkStream 完成。我需要执行查找操作并设置其clientRequestStream.Position = 0;,因为我必须读取该流并将其写入另一个远程NetworkStream

我不知道该如何解决这个问题。任何建议都会有所帮助。


编辑:我也尝试将NetworkStream复制到MemoryStream,然后对MemoryStream执行seek操作,没有例外,但是当我想从NetworkStream读取时,它的缓冲区总是空的。

我还使用反射器查看Stream.CopyTo 内部发生的情况。见以下代码:

    private void InternalCopyTo(Stream destination, int bufferSize)
    {
        int num;
        byte[] buffer = new byte[bufferSize];
        while ((num = this.Read(buffer, 0, buffer.Length)) != 0)
        {
            destination.Write(buffer, 0, num);
        }
    }

这就是 CopyTo 所做的。即使我使用CopyTo 问题仍然没有解决。因为它将源(Here NetworkStream)读取到最后。我有其他方法来处理这种情况吗?

【问题讨论】:

    标签: c# .net sockets network-programming tcpclient


    【解决方案1】:

    您是否从该流中读取直到结束?如果是这样,我建议您将整个内容复制到MemoryStream 中,然后您可以在那个上找到您的内容。在 .NET 4 中,使用 Stream.CopyTo 特别容易:

    MemoryStream dataCopy = new MemoryStream();
    using (var clientRequestStream = _tcpClient.GetStream())
    {
        clientRequestStream.CopyTo(dataCopy);
    }
    dataCopy.Position = 0;
    var requestHeader = dataCopy.GetUtf8String();
    

    NetworkStream 不可搜索是有道理的 - 它只是服务器提供给您的数据流。除非您可以告诉 服务器 倒带(这仅在某些情况下才有意义),否则没有办法寻找,除非有东西缓冲了您需要倒带的尽可能多的数据 - 这基本上就是复制到 @ 987654326@ 确实如此,以相当蛮力的方式。

    【讨论】:

    • Jon 我确实将 NetworkStream 复制到 MemoryStream,但是当我想读取缓冲区始终为空时。
    • Jon 我也测试了 CopyTo,但是将缓冲区复制到 MemoryStream 需要一天的时间。我不知道为什么。
    • @SaberAmani:那么网络流中有什么?如果服务器保持连接打开,它将不会完成复制。至于您的第一条评论 - 这表明您没有正确复制数据。没有看到你的代码,很难说是如何做到的。
    • @SaberAmani:你还没有真正描述你的情况,服务器要发送什么,或者流什么时候结束。如果服务器要保持连接打开,您需要知道要读取多少,并且只读取那么多
    • 谢谢@JonSkeet。在我的程序中,当我想多次使用netStream.CopyToAsync 时,它会在第二次使用netStream 时返回一个大小为零的文件。我试图将netStreamposition 设为0,但它给了我这个错误:This stream does not support seek operations。所以我用你的代码从netStream 中创建了一个MemoryStream,现在它运行良好。 ?
    【解决方案2】:

    正如您所发现的,NetworkStream 不可搜索。
    NetworkStream 直接从网络为您提供数据。

    您应该将数据读入MemoryStream 并重新使用它。

    【讨论】:

    • 您不能将 MemoryStream 分配给 NetworkStream。您需要直接使用 MemoryStream。
    • 我也测试了 CopyTo,但我需要一天时间将缓冲区复制到 MemoryStream。我不知道为什么。
    【解决方案3】:

    假设您不想正确地重写您的 GetUtf8String 方法以不需要 seek...

    最简单的方法是先将流复制到 MemoryStream,然后您可以随心所欲地寻找流。 Stream.CopyTo 将负责复制 (.Net4+)

    请注意,您需要通过将 Position 属性设置为 0 (copiedStream.Position=0) 或通过根据缓冲区和第一个内存流的长度创建新的(最好是只读的)来克隆流来寻找结果 MemoryStream。

    【讨论】:

    • @SaberAmani,已更新。请注意,Jon Skeet 的答案 (+1) 包含您需要的确切代码。
    • 我也测试了 CopyTo,但是将缓冲区复制到 MemoryStream 需要一天的时间,应用程序在我要复制的地方停止。我不知道为什么。
    【解决方案4】:

    您将无法设置 clientRequestStream.Position = 0,因为 NetworkStream 是只转发的。见这里:http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.position.aspx

    请注意将 NetworkStream 视为与常规流相同的方式。例如在 StreamReader 上的 Peek() 之类的操作可能会导致您的应用程序阻塞。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-30
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-11-27
      相关资源
      最近更新 更多