TCP/IP Message Framing

2019-07-07 01:06发布

问题:

I have made a TCP/IP Server/Client, its asynchronous but it concatenates the messages. How do I correctly go about adding a header at the start and then use a string builder at the end to un-concatenate complete messages.

Server Read Message:

  Private Sub ReadCallback(ByVal result As IAsyncResult)
    Try
        allDone.Set()
        Dim success As Boolean = result.AsyncWaitHandle.WaitOne(500, True)
        If success Then
            Dim client As ServerClient = TryCast(result.AsyncState, ServerClient)
            If client Is Nothing Then
                Return
            End If
            Dim networkStream As NetworkStream = client.NetworkStream
            Dim read As Integer = networkStream.EndRead(result)
            If read = 0 Then
                SyncLock Me.Clients
                    Me.Clients.Remove(client.ClientID)
                    Return
                End SyncLock
            End If
            If client.NetworkStream.CanRead Then

                dataString.Append(Me.Encoding.GetString(client.buffer, 0, read))

                networkStream.BeginRead(client.buffer, 0, client.buffer.Length, AddressOf ReadCallback, client)
                allDone.WaitOne(500, True)
            End If
        End If
    Catch ex As IO.IOException
        Dim client As ServerClient = TryCast(result.AsyncState, ServerClient)
        SyncLock Me.Clients
            Me.Clients.Remove(client.ClientID)
            Return
        End SyncLock
    Catch ex As Exception
        If Not Me.tcpListener.Server.Connected Then
            Return
        End If
    End Try
End Sub

Client Write Message:

    Public Function Write(value As String, encoding As Encoding) As Guid
    Dim buffer As Byte() = encoding.GetBytes(value)
    Return Me.Write(buffer)
End Function

Public Function Write(buffer As Byte()) As Guid
    Dim guid__1 As Guid = Guid.NewGuid()
    Dim networkStream As NetworkStream = Me.client.GetStream()
    Dim result As IAsyncResult = networkStream.BeginWrite(buffer, 0, buffer.Length, Nothing, guid__1)


    result.AsyncWaitHandle.WaitOne()
    networkStream.EndWrite(result)
    Return guid__1
End Function

回答1:

You need to define a (probably thin and simple) protocol on top of TCP/IP to allow you to know where one message starts and ends. TCP/IP can and will fragment the message you send such that the receiver could get part of a message, a whole message, or multiple messages. A simple approach is to write a message length, followed by the message. The receiver then reads into a byte buffer, and once the appropriate amount of bytes (based on the sent length) has been received the message can be pulled out and encoded into a string.