BinaryFormatter deserialize multiple objects from a stream

2.2k views Asked by At

I create a TcpClient with an IPEndpoint and open a NetworkStream with the opened connection.

stream = client.GetStream();

Stream is defined as a NetworkStream and client as a TcpClient. I want to use the Stream to send serialized objects every second. To do so I have an Timer that sends every second through a BinaryFormatter.

formatter.Serialize(stream, object);

Object in this case is a serialized class. On the other side I use an TcPListener and get the Stream with

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

Untill that point everything works as intended. The first object has the information I want and I am even able to access this information. As soon as I want to get a second Object from the same Stream I receive a NullReferenceException.

streamObject = deserialiser.Deserialize(stream);

I don't deserialize to a specific type so I could filter the objects and start different methods. *Notice that I use two different classes for sending and receiving and both classes run in different programs.

My question is: is it possible to send multiple objects through the same Stream with a timespan in between and deserialize it on the other side without opening and closing a stream everytime?

*Some additional info:

The Timer is running in a Windowsservice as a Thread. The first object will be sent as mentioned above but the second object won't.

As asked here is the stacktrace I receive.

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: 

Here is my Page_Load method as asked.

protected void Page_Load(object sender, EventArgs e) { recive = new ServerRecive(); recive.ReciveStreamObject(); FirstDate.Text = recive.ui.serverName; }

The connection is open as soon as I define recive. And here the code for the entire class 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;
 }
}
}

I dont have any specific size for the objects since they contain different information.

@nelus I did some workaround to get the Exception. Now i recived this Exception

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: 
1

There are 1 answers

0
Lordarking On BEST ANSWER

So I had built a second project to test if my Server even recive data and used a packet sniffer on localhost to confirm it. The class I now use to recive did nothing else. Only that it has a while loop that deserialize the stream over and over again. This solved my problem. It seems like the BinaryFormatter is albe to seek for the objects in the stream and deserialize every object without knowing the actual size or position of an object.

    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();
    }
}

The actual problem is not the way of how I recive the objects nor the way I deserialize them. The problem is the Windowsservice that actually abort the Thread that I use to send out my objects.

So a huge thanks to @neleus and @Grumbler85 who helped me to find the actual problem.