【问题标题】:memorystream copyto network stream issuesmemorystream 复制到网络流问题
【发布时间】:2011-11-29 08:38:23
【问题描述】:

这里的代码有问题。

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms,SerializableClassOfDoom);
    ms.Position = 0;
    byte[] messsize = BitConverter.GetBytes(ms.Length);
    ms.Write(messsize, 0, messsize.Length);
    NetworkStream ns = Sock.GetStream();
    ms.CopyTo(ns);
    //ms.Close();
}

我无法弄清楚这里发生了什么,或者为什么它不起作用。似乎是它没有复制,或者它关闭了网络流,或者其他什么。

很抱歉,我已经尝试调试它,但如果有人能在这里看到任何明显的问题,我将不胜感激。

顺便说一句,类序列化很好,并且 MemoryStream 包含数据,但由于某种原因,执行 ms.CopyTo(ns) 似乎不起作用?

基本上我想要做的是将类序列化为网络流,序列化数据的大小在它之前。如果有人有更好的方法,请告诉我!

【问题讨论】:

  • 我的猜测是,在您离开 using 块后,NetworkStream 被释放,因为它超出了范围。您可以尝试在 using 块结束之前刷新它。还是您的问题出在其他地方?
  • 尝试在 Using 结束之前同时刷新内存流和网络流,但似乎也没有。
  • ms.Write 之后需要另一个ms.Position = 0;。编辑:实际上,第一个 ms.Position = 0; 似乎是错误的,因为您正在覆盖刚刚写入的数据。
  • @leppie Omg,感觉很愚蠢。我只是认为它会将那里的数据向前移动(出于某种原因),但相反,你是对的,它只是覆盖了已经写入的内容。这一定是问题所在。
  • @kelton52:我会添加答案,以防万一:)

标签: c# networking memorystream networkstream binaryformatter


【解决方案1】:

您在错误的时间重置了流位置。

在您的情况下,您将“长度”写入流的开头。

以下应该有效:

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms,SerializableClassOfDoom);
    byte[] messsize = BitConverter.GetBytes(ms.Length);
    ms.Write(messsize, 0, messsize.Length);
    ms.Position = 0;
    NetworkStream ns = Sock.GetStream();
    ms.CopyTo(ns);
}

更新:

要在开头写入“长度”,请使用临时流/字节[]。

例子:

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms,SerializableClassOfDoom);
    byte[] data = ms.ToArray();
    byte[] messsize = BitConverter.GetBytes(ms.Length);
    ms.Position = 0;
    ms.Write(messsize, 0, messsize.Length);
    ms.Write(data, 0, data.Length);
    ms.Position = 0; // again!
    NetworkStream ns = Sock.GetStream();
    ms.CopyTo(ns);
}

更新 2:

更有效的方式。

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms,SerializableClassOfDoom);
    byte[] messsize = BitConverter.GetBytes(ms.Length);
    NetworkStream ns = Sock.GetStream();
    ns.Write(messsize, 0, messsize.Length);
    ms.Position = 0; // not sure if needed, doc for CopyTo unclear
    ms.CopyTo(ns); 
}

【讨论】:

  • 我希望消息大小位于流的开头,这可行吗?看起来这会把它抛在数据后面。
  • 对不起,再次缺乏细节。这基本上是我开始使用的代码,但我想重写它,所以我不必在 messsize 之外有任何数组。我正在尝试非常快地做到这一点,并且每次数据都超过 1mb(对于局域网连接)。我希望我能以某种方式操纵流,从而使我不必将流放入数组中,这是最昂贵的调用。
  • @kelton52:使用 2 个内存流可能是最好的选择,或者不要使用Stream.CopyTo。我会(再次)更新答案。
  • 是的,Update 2 是我刚刚提出的,但你为什么说不要使用 Stream.CopyTo?
  • @kelton52:由于缺乏明确的文档。请参阅评论以设置位置。毕竟,在它下面只是简单地做Stream.ReadStream.Write
【解决方案2】:

也许您需要在调用 CopyTo 之前将内存流倒回到开头(使用 ms.Seek(0, SeekOrigin.Start))

【讨论】:

    【解决方案3】:

    我没有看到真正的问题,但我在这里看到了一点重构问题。

    尝试使用

    Stream.Flush()
    Stream.Close()
    

    在完成任何流之前。

    还用try-catch这样的语句包围它,以确保即使出现异常也能关闭和刷新!

    Stream s = new Stream();
    try{
        s.Write();
    }catch(Exception ex){
        //Oh god, we are doomed!
    }finally{
        s.Flush();
        s.Close();
    }
    

    你的代码看起来像

    NetworkStream ns = null;
    using (MemoryStream ms = new MemoryStream())
    {
        try{
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms,SerializableClassOfDoom);
            ms.Position = 0;
            byte[] messsize = BitConverter.GetBytes(ms.Length);
            ms.Write(messsize, 0, messsize.Length);
            ns = Sock.GetStream();
            ms.CopyTo(ns);
            //ms.Close();
        }catch(Exception ex){
            throw;
        }finally{
            ms.Flush();
            if(ns != null)
                ns.Flush();
    
            ms.Close();
        }
    }
    

    在这之后你应该能够找到你的问题。

    【讨论】:

    • 我认为有两点错误,ns 没有解析到 finally 块。另外,我不想关闭网络流。我会修改它并试一试。
    • 更新了 ns 外面,没有关闭。
    • 没关系,我可能没有提供足够的细节或其他东西。
    猜你喜欢
    • 2015-10-27
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多