Hello all,

I'm having a problem with sending a serialized object over a NetworkStream. I'm using the BinaryFormatter and the object is serialized and deserialized fine writing to a file.

If I use a streamwriter to send text it works fine after the Flush()

nStream = _tcpClient.GetStream()
    Dim sw As StreamWriter = New StreamWriter(nStream)
    sw.Write("Text to sent")
    sw.[B]Flush()[/B]

Now when I use the BinaryFormatter the object is serialized to the NetworkStream but the server never gets it

nStream = _tcpClient.GetStream()
    Dim bf As New BinaryFormatter()
    bf.Serialize(nStream, MyObject)

It look like it's waiting for a flush or something.

I hope someone can help me

Recommended Answers

All 3 Replies

Ossehaas,

Check the StreamingContext class for additional info.... I think it will help ya out....

According MSDN:

Imports System
Imports System.Text
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization
Imports System.IO
Imports System.Security.Permissions


Class Program

    Shared Sub Main(ByVal args() As String) 
        Try
            SerializeAndDeserialize()
        Catch exc As System.Exception
            Console.WriteLine(exc.Message)
        Finally
            Console.WriteLine("Press <Enter> to exit....")
            Console.ReadLine()
        End Try

    End Sub 

    Shared Sub SerializeAndDeserialize() 
        Dim myObject As Object = DateTime.Now
        ' Create a StreamingContext that includes a
        ' a DateTime. 
        Dim sc As New StreamingContext(StreamingContextStates.CrossProcess, myObject)
        Dim bf As New BinaryFormatter(Nothing, sc)
        Dim ms As New MemoryStream(New Byte(2047) {})
        bf.Serialize(ms, New [MyClass]())
        ms.Seek(0, SeekOrigin.Begin)
        Dim f As [MyClass] = CType(bf.Deserialize(ms), [MyClass])
        Console.WriteLine(vbTab + " MinValue: {0} " + vbLf + vbTab + " MaxValue: {1}", f.MinValue, f.MaxValue)
        Console.WriteLine("StreamingContext.State: {0}", sc.State)

        Dim myDateTime As DateTime = CType(sc.Context, DateTime)
        Console.WriteLine("StreamingContext.Context: {0}", myDateTime.ToLongTimeString())

    End Sub 
End Class 

<Serializable(), SecurityPermission(SecurityAction.Demand, SerializationFormatter := True)>  _
Class [MyClass]
    Implements ISerializable
    Private minValue_value As Integer
    Private maxValue_value As Integer

    Public Sub New() 
        minValue_value = Integer.MinValue
        maxValue_value = Integer.MaxValue    
    End Sub     

    Public Property MinValue() As Integer 
        Get
            Return minValue_value
        End Get
        Set
            minValue_value = value
        End Set
    End Property 

    Public Property MaxValue() As Integer 
        Get
            Return maxValue_value
        End Get
        Set
            maxValue_value = value
        End Set
    End Property

    Sub GetObjectData(ByVal si As SerializationInfo, ByVal context As StreamingContext)  Implements ISerializable.GetObjectData
        si.AddValue("minValue", minValue_value)
        si.AddValue("maxValue", maxValue_value)

    End Sub   

    Protected Sub New(ByVal si As SerializationInfo, ByVal context As StreamingContext) 
        minValue_value = Fix(si.GetValue("minValue", GetType(Integer)))
        maxValue_value = Fix(si.GetValue("maxValue", GetType(Integer)))
    End Sub 
End Class

Thanxs for the reply, Im not sure how too use the code you posted, I think it's for testing the Serialization process, but the object is Serialized and deserialized fine when I'm writing it to a file. I have a working example but I have to translate it from C# to VB. I will post it when I'm done.

Ok, here goes the code, it works and it's also Generic.

First build a class library and add the following classes

Namespace Library    
   <Serializable()> _
    Public Class UserLogin
        Private _name As String
        Private _password As String

        Public Sub New(ByVal UserName As String, ByVal Password As String)
            _name = UserName
            _password = Password
        End Sub

        Public ReadOnly Property UserName() As String
            Get
                Return _name
            End Get
        End Property

        Public ReadOnly Property Password() As String
            Get
                Return _password
            End Get
        End Property
    End Class

    Public Delegate Sub DataReceivedDelegate(ByVal sender As Object, ByVal args As DataReceivedEventArgs)


    Public Class DataReceivedEventArgs
        Inherits EventArgs

        Private _data As Object
        Public Property Data() As Object
            Get
                Return _data
            End Get
            Set(ByVal value As Object)
                _data = value
            End Set
        End Property

        Public Sub New()

        End Sub

        Public Sub New(ByVal Data As Object)
            _data = Data
        End Sub
    End Class

    Public Class SimpleServer(Of T)
        Private _ip As IPAddress
        Public ReadOnly Property IP() As IPAddress
            Get
                Return _ip
            End Get
        End Property
        Private _listener As TcpListener

        Private _data As IEnumerable(Of T)
        Public Property Data() As IEnumerable(Of T)
            Get
                Return _data
            End Get
            Set(ByVal value As IEnumerable(Of T))
                _data = value
            End Set
        End Property

        Private _port As Integer
        Public ReadOnly Property Port() As Integer
            Get
                Return _port
            End Get
        End Property

        Public Sub New(ByVal port As Integer, ByVal ip As IPAddress)
            _ip = ip
            _port = port
            _listener = New TcpListener(ip, port)
        End Sub

        Public Sub SendData()
            Try
                While True
                    Using client As TcpClient = _listener.AcceptTcpClient()
                        Using netStream As NetworkStream = client.GetStream()
                            While True
                                Using memStream As MemoryStream = New MemoryStream()
                                    For Each item As T In Data
                                        Dim formatter As New BinaryFormatter()
                                        formatter.Serialize(memStream, item)
                                        Dim data() As Byte = memStream.GetBuffer()
                                        Dim length() As Byte = BitConverter.GetBytes(data.Length)
                                        netStream.Write(length, 0, length.Length)
                                        netStream.Write(data, 0, data.Length)
                                        memStream.Position = 0
                                    Next

                                    Exit While
                                End Using
                            End While
                        End Using
                        Exit While
                    End Using
                End While
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            Finally
                _listener.Stop()
            End Try
        End Sub

        Public Sub Listen()
            _listener.Start()
            SendData()
        End Sub
    End Class

    Public Class SimpleClient(Of T)
        Private _port As Integer
        Public ReadOnly Property Part() As Integer
            Get
                Return _port
            End Get
        End Property

        Private _ip As IPAddress
        Public ReadOnly Property IP() As IPAddress
            Get
                Return _ip
            End Get
        End Property

        Private _serverPort As Integer
        Public ReadOnly Property ServerPort() As Integer
            Get
                Return _serverPort
            End Get
        End Property

        Private _serverIP As IPAddress
        Public ReadOnly Property ServerIP() As IPAddress
            Get
                Return _serverIP
            End Get
        End Property
        Private _dataReceivedEvent As DataReceivedDelegate
        Public Sub PassDelegate(ByVal del As DataReceivedDelegate)
            _dataReceivedEvent = del
        End Sub

        Public Sub New(ByVal port As Integer, ByVal ip As IPAddress, ByVal serverPort As Integer, ByVal severIP As IPAddress)
            _port = port
            _ip = ip
            _serverPort = serverPort
            _serverIP = severIP
        End Sub

        Private Sub OnDataReceivedEvent(ByVal args As DataReceivedEventArgs)
            If Not _dataReceivedEvent.Equals(Nothing) Then
                _dataReceivedEvent(Me, args)
            End If
        End Sub

        Private Function ReceiveFixedData(ByVal netStream As NetworkStream, ByVal count As Integer) As Byte()
            If (netStream.Equals(Nothing)) Then
                Throw New ArgumentNullException("stream")
            End If

            If count <= 0 Then
                Throw New ArgumentOutOfRangeException("count", "Parameter's value cannot be 0 or less than 0.")
            End If

            Dim buffer(count) As Byte
            Dim receivedCount As Integer
            Dim position As Integer = 0

            ' read until all data is received.   
            Do While (position < count)
                receivedCount = netStream.Read(buffer, position, count - position)
                If receivedCount = 0 Then
                    Return Nothing
                End If
                position += receivedCount
            Loop
            Return buffer
        End Function

        Public Sub ConnectServer()
            Using client As New TcpClient(New IPEndPoint(_ip, _port))
                client.Connect(_serverIP, _serverPort)
                Using netStream As NetworkStream = client.GetStream()
                    While True
                        ' get the number of bytes to be read in order to retrieve all message
                        Dim data() As Byte = ReceiveFixedData(netStream, 4)
                        If data Is Nothing Then
                            Exit Sub
                        End If
                        Dim messageLength As Integer = BitConverter.ToInt32(data, 0)
                        If messageLength > 0 Then
                            data = ReceiveFixedData(netStream, messageLength)
                            If data.Equals(Nothing) Then
                                Return
                            End If
                            Dim formatter As New BinaryFormatter()
                            Using memStream As MemoryStream = New MemoryStream(data)
                                Dim message As T = CType(formatter.Deserialize(memStream), T)
                                OnDataReceivedEvent(New DataReceivedEventArgs(message))
                            End Using
                        End If
                    End While
                End Using
            End Using
        End Sub
    End Class
End Namespace

Now build the class library.

Create a Client and a Server application. In both add reference to the DLL you created with the class library. (VS Menu > Project > Add Reference)

Server:

Import  yourDLLNamespace.Library

Public Class Program

    Public Sub Main() 
        Dim data As New List(Of UserLogin)

        For i As Integer = 0 To 3
            Dim ul As New UserLogin("Name " & i.ToString(), "pw" & i.ToString())
            data.Add(ul)
        Next

        Dim server As SimpleServer(Of UserLogin) = New SimpleServer(Of UserLogin)(7777, IPAddress.Parse("127.0.0.1"))
        server.Data = data

        Try
            server.Listen()

        Catch ex As Exception
            Console.WriteLine(ex.Message())
        End Try
    End Sub
End Class

Client:

Import  yourDLLNamespace.Library

Public Class Program
   
    Public Sub Main()
        Dim client As SimpleClient(Of UserLogin) = New SimpleClient(Of UserLogin)(7778, IPAddress.Parse("127.0.0.1"), 7777, IPAddress.Parse("127.0.0.1"))
        client.PassDelegate(AddressOf client_DataReceivedEvent)

        Try
            client.ConnectServer()
        Catch ex As Exception
            Console.WriteLine(ex.Message())
        End Try
    End Sub

    Public Sub client_DataReceivedEvent(ByVal sender As Object, ByVal args As DataReceivedEventArgs)
        Dim ul As UserLogin = CType(args.Data, UserLogin)
        Console.WriteLine(ul.UserName)
    End Sub
End Class

I hope that with this code some other people don't have to spent days searching on the web for a working example like I did.

Thanx for Anton Gochev’s weblog, thats where I translated it from.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.