【问题标题】:BinaryFormatter.Deserialize hangs the whole threadBinaryFormatter.Deserialize 挂起整个线程
【发布时间】:2015-06-04 21:14:52
【问题描述】:

我有两个通过命名管道连接的简单应用程序。在客户端,我有一个方法可以每隔 n 毫秒检查一次传入消息:

private void timer_Elapsed(Object sender, ElapsedEventArgs e)
{
      IFormatter f = new BinaryFormatter();
      try
      {
           object temp = f.Deserialize(pipeClient); //hangs here
           result = (Func<T>)temp;
      }
      catch
      {
      }
}

一开始管道是空的,f.Deserialize 方法会挂起整个应用程序。我什至不能检查那个管道是空的?这个问题有解决办法吗?

UPD:试过XmlSerializer,一切都一样。

【问题讨论】:

  • 启动后台线程检查管道
  • @antlersoft 当然也挂了
  • 后台线程应该挂起,直到管道上有可用数据
  • 仅供参考,截至 2020 年 11 月,MS 在您的代码中推荐 not using using BinaryFormatter。事实上,它是不允许在 ASP.NET 中使用的。相反,请考虑使用 JsonSerializer 或 XmlSerializer。有关详细信息,请参阅BinaryFormatter security guide

标签: c# xmlserializer binaryformatter


【解决方案1】:

困扰您的是两个格式化程序在内部进行的pipeClient.Read( 调用。

这是Stream 的预期行为,当您调用Read 时:

返回值
类型:System.Int32
读入缓冲区的总字节数。这可能小于字节数 如果该字节数当前不可用,则请求,如果该字节数不可用,则为 0 已到达流的末尾。

因此,如果流类型支持超时,流将阻塞直到数据显示或抛出超时异常。它永远不会在不读取任何内容的情况下返回,除非您“处于流的末尾”,对于PipeStream(或类似的NetworkStream),只有在连接关闭时才会发生。

您解决问题的方法是不要使用计时器来检查是否有新消息到达,只需启动一个后台线程并让它处于循环状态,它会自行阻塞直到消息出现。

class YourClass
{
    public YourClass(PipeStream pipeClient)
    {
        _pipeClient = pipeClient;
        var task = new Task(MessageHandler, TaskCreationOptions.LongRunning);
        task.Start();
    }

    //SNIP...

    private void MessageHandler()
    {
        while(_pipeClient.IsConnected)
        {
            IFormatter f = new BinaryFormatter();
            try
            {
                 object temp = f.Deserialize(_pipeClient);
                 result = (Func<T>)temp;
            }
            catch
            {
                //You really should do some kind of logging.
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2012-04-18
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    相关资源
    最近更新 更多