0

I have a program that's using TCP for communication between the client and server. Client sends a byte array of a BMP image. The listener reads the bytes in chunks and joins the bytes together to get the image. When the server/listener receives the image, it is corrupted almost halfway through.

When using the localhost to test on my computer the corruption is less likely to happen (greater the byte array size = more corruption), however when over the internet it is corrupted 99% of the time regardless of size. I have also tried splitting the byte array and sending it to the server in chunks, this seems to fix the corruption on localhost but is still the same when over the internet.

Can soomeone tell me what I'm doing wrong here?

The listener code running in a timer:

If Listener.Pending = True Then
Client = Listener.AcceptTcpClient()
Message = ""
Dim ClientNetworkStream As NetworkStream = Client.GetStream
ReDim ReadBytes(-1)
If ClientNetworkStream.CanRead = True Then
    Dim ReadBuffer(65535) As Byte
    Dim NumberOfBytesRead As Integer = 0
    Do
    NumberOfBytesRead = ClientNetworkStream.Read(ReadBuffer, 0, ReadBuffer.Length)
    If Not NumberOfBytesRead = 0 Then
        If Not NumberOfBytesRead = -1 Then
            ReadBytes = AppendByteArrays(ReadBytes, ReadBuffer, NumberOfBytesRead)
            If ConvoOngoing = False Then
            ReDim CurrentConvoBytes(-1)
            ConvoOngoing = True
            CurrentConvoBytes = ReadBytes
        Else
            CurrentConvoBytes = AppendByteArrays(CurrentConvoBytes, ReadBytes)
        End If
    End If
End If
Loop While ClientNetworkStream.DataAvailable
    If ClientNetworkStream.DataAvailable = False Then
        If ConvoOngoing = True Then
            If ReadBytes.Length > 0 Then
                CurrentConvoBytes = AppendByteArrays(CurrentConvoBytes, ReadBytes)
            End If
        ConvoOngoing = False
        PictureBox1.Image = ConvertByteArrayToBMP(CurrentConvoBytes)
        End If
    End If
End If
End If

Here is the sender code:

    Private Sub SendWhole(ByVal BytesToSend() As Byte, ByVal Optional isFile As Boolean = False)
    Client = New TcpClient(TextBox2.Text, TextBox3.Text)
    Dim ClientStream As NetworkStream = Client.GetStream
    ClientStream.Write(BytesToSend, 0, BytesToSend.Length)
    ClientStream.Close()
End Sub

And the code for AppendByteArrays used in the code:

    Public Function AppendByteArrays(ByVal OriginalArray As Byte(), ByVal ArrayToAppend As Byte(), ByVal Optional AmountOfValuesToAdd As Integer = -1) As Byte()
    Dim IndexToStart As Integer = OriginalArray.Length
    Dim Modifier As Integer = 0
    If Not AmountOfValuesToAdd = -1 Then
        Modifier = AmountOfValuesToAdd - 1
    Else
        Modifier = -1
    End If
    If Modifier = -1 Then
        ReDim Preserve OriginalArray((OriginalArray.Length) + (ArrayToAppend.Length - 1))
        For i = 0 To ArrayToAppend.Length - 1
            OriginalArray(IndexToStart + i) = ArrayToAppend(i)
        Next
    Else
        ReDim Preserve OriginalArray((OriginalArray.Length) + Modifier)
        For i = 0 To Modifier
            OriginalArray(IndexToStart + i) = ArrayToAppend(i)
        Next
    End If
    Return OriginalArray
End Function

Edit: Here's the bit where I can't seem to figure out the math right

        If Listener.Pending = True Then
        Client = Listener.AcceptTcpClient()
        Dim ClientNetworkStream As NetworkStream = Client.GetStream
        ReDim ReadBytes(-1)
        If ClientNetworkStream.CanRead = True Then
            Dim ReadBuffer(65535) As Byte
            Dim NumberOfBytesRead As Integer = 0
            Do
                NumberOfBytesRead = ClientNetworkStream.Read(ReadBuffer, 0, ReadBuffer.Length)
                If Not NumberOfBytesRead = 0 Then
                    If Not NumberOfBytesRead = -1 Then
                        If ReadingPacket = False Then
                            If PacketHasLeftOvers = True Then
                                PacketHasLeftOvers = False
                                ReadBuffer = AppendByteArrays(PacketLeftOvers, ReadBuffer)
                                ReDim PacketLeftOvers(-1)
                            End If
                            ReadingPacket = True
                            PacketToReadSize = BitConverter.ToInt32(ReadBuffer, 0)
                            PacketType = ReadBuffer(4)
                            ReDim CurrentConvoBytes(-1)
                            ReadBytes = AppendByteArrays(ReadBytes, ReadBuffer.Skip(5).ToArray, NumberOfBytesRead - 5)
                            CurrentConvoBytes = ReadBytes
                            PacketReadSize = ReadBytes.Length - 1
                            If PacketReadSize = PacketToReadSize Then
                                'Check if already finished reading
                                PictureBox1.Image = ConvertByteArrayToBMP(CurrentConvoBytes)
                                PacketReadSize = 0
                                ReadingPacket = False
                            End If
                        Else
                            Dim PacketScore As Integer = PacketReadSize + NumberOfBytesRead
                            If PacketScore < PacketToReadSize Then
                                ReadBytes = AppendByteArrays(ReadBytes, ReadBuffer, NumberOfBytesRead)
                                CurrentConvoBytes = AppendByteArrays(CurrentConvoBytes, ReadBytes)
                                PacketReadSize += ReadBytes.Length - 1
                            ElseIf PacketScore > PacketToReadSize Then
                                ReadBytes = AppendByteArrays(ReadBytes, ReadBuffer, NumberOfBytesRead - (PacketToReadSize - PacketReadSize))
                                CurrentConvoBytes = AppendByteArrays(CurrentConvoBytes, ReadBytes)
                                PacketHasLeftOvers = True
                                PacketLeftOvers = ReadBuffer.Skip(PacketToReadSize - PacketReadSize).ToArray
                                PictureBox1.Image = ConvertByteArrayToBMP(CurrentConvoBytes)
                                PacketReadSize = 0
                                ReadingPacket = False
                            ElseIf PacketScore = PacketToReadSize Then
                                ReadBytes = AppendByteArrays(ReadBytes, ReadBuffer, NumberOfBytesRead)
                                CurrentConvoBytes = AppendByteArrays(CurrentConvoBytes, ReadBytes)
                                PictureBox1.Image = ConvertByteArrayToBMP(CurrentConvoBytes)
                                PacketReadSize = 0
                                ReadingPacket = False
                            End If
                        End If
                    End If
                Else
                    Throw New Exception
                End If
            Loop While ClientNetworkStream.DataAvailable
        End If
    End If
Metalel
  • 1
  • 2
  • You need to implement some kind of message framing. TCP is a stream-based network protocol, meaning that on the application layer the data is represented in a continuous stream of bytes. There's no notion of packets. When you call `Read()` it will read whatever it has currently downloaded, which is usually less than what you've sent with each `Write()`. See my answer here: Possible duplicate of [C# Deserializing a struct after receiving it through TCP](https://stackoverflow.com/questions/37341382/c-sharp-deserializing-a-struct-after-receiving-it-through-tcp) – Visual Vincent May 09 '18 at 06:49
  • @VisualVincent So I went with what you said in your previous answers, to have the first 4 bytes of the message determine the size of the current "packet", and 1 byte after that to determine the type of the "packet". However I seem to not be able to get the amount-of-bytes-read right to check if the total-amount-of-bytes-to-read is equal to it. Can you look at the Edit section please. – Metalel May 10 '18 at 14:18
  • That is a bit too much code for me to both test and try to understand. You have to step through your code using [breakpoints](https://msdn.microsoft.com/en-us/library/5557y8b4.aspx) and [inspect your variables](https://blogs.msdn.microsoft.com/devops/2016/07/15/7-ways-to-look-at-the-values-of-variables-while-debugging-in-visual-studio/) to try to determine the cause of the problem. Also it appears you have a lot of both repeating and unnecessary code. You ought to try to simplify it. – Visual Vincent May 10 '18 at 16:52
  • And if you haven't already, [check the source code for my packet-based TCP client](http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient.zip) which I used in [this answer](http://stackoverflow.com/a/35240061/3740093) (it was linked in the answer I pointed you to earlier). It is mainly the `PacketListener()` method that is of your interest. – Visual Vincent May 10 '18 at 16:56

0 Answers0