二进制格式化程序从流中反序列化多个对象

本文关键字:反序列化 对象 格式化 程序 二进制 | 更新日期: 2023-09-27 18:30:53

我用一个IPEndpoint创建一个TcpClient,并使用打开的连接打开一个NetworkStream。

stream = client.GetStream();
Stream

定义为 NetworkStream,客户端定义为 TcpClient。我想使用 Stream 每秒发送序列化对象。为此,我有一个计时器,它每秒通过二进制格式化程序发送一次。

formatter.Serialize(stream, object);

在本例中,对象是序列化类。另一方面,我使用TcPListener并获得流

stream = listener.AcceptTcpClient().GetStream();

在那之前,一切都按预期工作。第一个对象有我想要的信息,我甚至可以访问这些信息。一旦我想从同一个流中获取第二个对象,我就会收到一个 NullReferenceException

streamObject = deserialiser.Deserialize(stream);

我不反序列化为特定类型,因此我可以过滤对象并启动不同的方法。 *请注意,我使用两个不同的类进行发送和接收,并且这两个类在不同的程序中运行。

我的问题是:是否有可能通过同一流发送多个对象,中间有时间跨度,并在另一端反序列化它,而无需每次都打开和关闭流?

*一些附加信息:

计时器作为线程在 Windowsservice 中运行。第一个对象将如上所述发送,但第二个对象不会。

正如这里所问的,是我收到的堆栈跟踪。

System.NullReferenceException was not handled by user code.
  HResult=-2147467261
  Message=The Object reference not set to an object instance ..
  Source=App_Web_qtieteli
  StackTrace:
       at _Default.Page_Load(Object sender, EventArgs e) in c:'Users'Documents'Visual Studio 2012'WebSites'System_GUI'Default.aspx.cs:Row 14.
       at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
       at System.Web.UI.Control.OnLoad(EventArgs e)
       at System.Web.UI.Control.LoadRecursive()
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: 

这是我Page_Load方法

受保护的无效Page_Load(对象发送器,事件参数 e) { recive = new ServerRecive(); 收。ReciveStreamObject(); FirstDate.Text = recive.ui.serverName; }

一旦我定义接收,连接就会打开。这里是整个类ServerRecive的代码。

  public class ServerRecive
 {
public ObjectTypeUI ui {get; set;}
public ObjectTypeSI si { get; set; }
public ObjectTypeDI di { get; set; }
TcpListener listener;
NetworkStream stream;
BinaryFormatter deserialiser;
public ServerRecive ()
{
 deserialiser = new BinaryFormatter();
 Initialize();
}
private void Initialize ()
{
listener = new TcpListener (IPAddress.Any, *port*);
listener.Start();
stream = listener.AcceptTcpClient().GetStream();
}

public void ReciveStreamObject()
{
object Object = new object();
try
 {
  Object = deserialiser.Deserialize(stream);
 }
 catch (Exception e) {}
 if (Object.GetType() == typeof(ObjectTypeSI))
 {
  si = (ObjectTypeSI)Object;
 }
 else if (Object.GetType() == typeof(ObjectTypeUI))
 {
  ui = (ObjectTypeUI)Object;
 }
 else if(Object.GetType() == typeof(ObjectTypeDI))
 {
  di = (ObjectTypeDI)Object;
 }
}
}

我没有对象的任何特定大小,因为它们包含不同的信息。

@nelus 我做了一些解决方法来获取异常。现在我收到了这个例外

System.Runtime.Serialization.SerializationException was not handled.
HResult=-2146233076
Message=The input stream is not a valid binary format. The start content     
(in     Bytes) is: 1B-65-72-69-61-6C-4F-62-6A-65-63-74-2E-53-65-72-76 ...
Source=mscorlib
StackTrace:
at
System.Runtime.Serialization.Formatters.Binary.SerializationHeaderRecord.Read(__BinaryParser input)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadSerializationHeaderRecord()
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   at System_GUI.ServerRecive.ReciveStreamObject() in c:'Users'rbr'Documents'Visual Studio 2012'WebSites'System_GUI'App_Code'Netzwerk'ServerRecive.cs:Zeile 51.
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
InnerException: 

二进制格式化程序从流中反序列化多个对象

所以我构建了第二个项目来测试我的服务器是否接收数据,并使用本地主机上的数据包嗅探器来确认它。我现在用来接收的类没有做任何其他事情。只是它有一个 while 循环,可以一遍又一遍地反序列化流。这解决了我的问题。似乎 BinaryFormatter 在不知道对象的实际大小或位置的情况下寻找流中的对象并反序列化每个对象。

    class Program
{
    TcpListener listener = new TcpListener(IPAddress.Any, 4456);
    NetworkStream stream;
    ObjectTypeUI ui;
    ObjectTypeDI di;
    ObjectTypeSI si;
    BinaryFormatter deserializer = new BinaryFormatter();
    public Program()
    {
     listener.Start();
     stream = listener.AcceptTcpClient().GetStream();
     while (true)
     {
         object streamObject = deserializer.Deserialize(stream);
         if (streamObject.GetType() == typeof(ObjectTypeSI))
         {
          si = (ObjectTypeSI)streamObject;
          Console.WriteLine(si.Kunde);
         }
         else if (streamObject.GetType() == typeof(ObjectTypeUI))
         {
          ui = (ObjectTypeUI)streamObject;
          Console.WriteLine(ui.CpuUsage);
         }
         else if(streamObject.GetType() == typeof(ObjectTypeDI))
         {
          di = (ObjectTypeDI)streamObject;
         }
     }

    }
    static void Main(string[] args)
    {
     new Program();
     Console.ReadLine();
    }
}

实际问题不是我如何接收对象的方式,也不是我反序列化它们的方式。问题是Windows服务实际上中止了我用来发送对象的线程。

非常感谢@neleus和@Grumbler85帮助我找到了实际问题。