none
Problem Sending so long RTF by TCP connection (VB.NET 2015) RRS feed

  • Question

  • Hi. Firstly thank's for your time. 
    I am workin on a LAN Chat app  under TCP. This develpment have basically two form:
    Form to see the connected users (fm_users)

    Form to send/receive privates messages. (fm_private)

    On fm_private i have two RichTextBOX:
    rtb_conversation: to log the historial of the private conversation
    rtb_msg: to write and send then messages. On rtb_msg i can to paste pictures to send it througth TCP (I send the rtf not the txt) just like Skype
    but when i do it, the rtf is so long. Ex:


    {\rtf1\ansi\ansicpg1252\deff0\deflang3082{\fonttbl{\f0\fnil\fcharset0 Bookman Old Style;}}
    {\colortbl ;\red0\green255\blue0;}
    \viewkind4\uc1\pard\cf1\f0\fs36{\pict\wmetafile8\picw-21092\pich27777\picwgoal25197\pichgoal15748 
    010009000003286028000000126028000000050000000b0200000000050000000c02816c9cad12
    602800430f2000cc0000001a04900600000000816c9cad0000000028000000900600001a040000
    0100180000000000e0bf5000c40e0000c40e000000000000000000000502000502000502000502
    000502000502000502000502000502000502000502000502000502000502000502000502000502
    000502000502000502000502000602000602000602000602000602000602000602000502000502
    000502000502000502000502000502000502000502000502000502000602000502000502000502
    0005020005020005020005000502000502000502000502000502000502000502000502000502000502000502000502000502
    000502000502000502000502000602000602000602000602000602000602000602000502000502
    000502000502000502000502000502000502000502000502000502000602000502000502000502
    000502000502000502000000502000502000502000502000502000502000502000502000502000502000502000502000502
    000502000502000502000502000602000602000602000602000602000602000602000502000502
    000502000502000502000502000502000502000502000502000502000602000502000502000502
    000502000502000502000......

    and it does not come complete. 
    someone has solved this sometime?
    I hope you can help me.

    Public Sub EnviarInfo(ByVal txt As String, ByVal IPRemota As String, ByVal Puerto As Integer)
    
    
            Dim clientSocket = New TcpClient
            Dim iP As IPAddress = IPAddress.Any
            Dim isIp As Boolean = IPAddress.TryParse(IPRemota, iP)
    
            With clientSocket
                Try
                    If isIp Then
                        .Connect(IPAddress.Parse(IPRemota), Puerto)
                    Else
                        .Connect(IPRemota, Puerto)
                    End If
    
                    Dim data() As Byte = Encoding.ASCII.GetBytes(txt)
    
                    .NoDelay = True
                    .GetStream().Write(data, 0, data.Length)
                    .GetStream().Close()
    
                    .Close()
                    EstadoEnvio = True
                Catch ex As Exception
                    MsgBox("Enviar datos: " & ex.Message, MsgBoxStyle.Exclamation)
                    EstadoEnvio = False
                Finally
                    RaiseEvent EnvioOk(EstadoEnvio)
                End Try
    
            End With
        End Sub

     Private Sub Aceptar(ByVal ar As IAsyncResult)
    
            Dim sb As New StringBuilder
            Dim buf() As Byte
            Dim datalen As Integer
    
            Dim listener As TcpListener
            Dim clientSocket As TcpClient
            If Not Conectado Then Exit Sub
            Try
                listener = CType(ar.AsyncState, TcpListener)
                clientSocket = listener.EndAcceptTcpClient(ar)
                clientSocket.ReceiveTimeout = 5000
                IPRemota = clientSocket.Client.RemoteEndPoint
                IPLocal = clientSocket.Client.LocalEndPoint
    
            Catch ex As ObjectDisposedException
                MsgBox("Aceptar llamado " & ex.Message, MsgBoxStyle.Exclamation)
                Exit Sub
            End Try
    
            Try
                With clientSocket
                    datalen = 0
                    While datalen = 0
                        datalen = .Available
                    End While
                    buf = New Byte(datalen - 1) {}
                    .GetStream().Read(buf, 0, buf.Length)
                    sb.Append(Encoding.ASCII.GetString(buf, 0, buf.Length))
                    .Close()
                End With
                EstadoRecepcion = True
            Catch ex As TimeoutException
                MsgBox("Aceptar llamado timeout: " & ex.Message, MsgBoxStyle.Exclamation)
                EstadoRecepcion = False
                clientSocket.Close()
                Exit Sub
            Catch ex As Exception
                MsgBox("Aceptar llamado: " & ex.Message, MsgBoxStyle.Exclamation)
                EstadoRecepcion = False
                clientSocket.Close()
                Exit Sub
            Finally
                RaiseEvent RecepcionOk(EstadoRecepcion)
            End Try
            SincroContext.Post(New SendOrPostCallback(AddressOf RecibiendoDatos), sb.ToString)
            Servidor.BeginAcceptTcpClient(New AsyncCallback(AddressOf Aceptar), Servidor)
        End Sub

    Wednesday, April 25, 2018 8:38 PM

Answers

  • Really you should add a byte header and end sequence to the RTFBytes such that the receiving side knows the byte header which could advise the receiving site of the total amount of bytes in the byte header, rtf bytes and end sequence. Then the receiving side would know once it receives the end sequence it is done even if the byte count was off for some reason.

    La vida loca

    • Marked as answer by CM16 Thursday, April 26, 2018 7:00 PM
    Thursday, April 26, 2018 1:17 AM

All replies

  • On rtb_msg i can to paste pictures to send it througth TCP (I send the rtf not the txt) just like Skype
    but when i do it, the rtf is so long.

    Your loop that waits for the data terminates when any data has been received (.Available <> 0).  It should only terminate when all the data has been received. See:
    https://docs.microsoft.com/en-us/dotnet/framework/network-programming/using-a-synchronous-client-socket

    For instance, if the data stream started with a count of the characters that are in the message, then the receive routine could be written so that it loops until that many characters have been received.

    Wednesday, April 25, 2018 10:15 PM
  • Really you should add a byte header and end sequence to the RTFBytes such that the receiving side knows the byte header which could advise the receiving site of the total amount of bytes in the byte header, rtf bytes and end sequence. Then the receiving side would know once it receives the end sequence it is done even if the byte count was off for some reason.

    La vida loca

    • Marked as answer by CM16 Thursday, April 26, 2018 7:00 PM
    Thursday, April 26, 2018 1:17 AM
  • Hi. Thank's for your response. I will try it. The strange of this is that to small pictures, the message arrives ok.
    For example, if i send a part of a screen (printscreen) sends and arrives ok. But if i send the complete print screen, the rtf comes incomplete.

    TEXT,RTF,COMPLETE,INCOMPLETE,SENDS,ARRIVES

    Thursday, April 26, 2018 11:38 AM
  • You don't transmit anything from the send side to tell the receive side when to quit receiving. IP requires the applications to perform the messaging stuff for when data transmitted has finished. That way the receive side knows when massive data is being transmitted to it and when it receives some sequence or message that the massive data is done. IP packets are typicaly 1512 bytes if my memory is accurate and part of that is IP overhead and the rest data. The receive side has no way of knowing when to disconnect or take the received data and do something with it. It knows nothing unless you implement some method for it to know.

    La vida loca

    Thursday, April 26, 2018 6:31 PM
  • Thank's everybody for your responses.
    I make it work, just i maked some changes to the loop to receive whit streamnetwork.

    i copy the code for more details:

     Private Sub Aceptar(ByVal ar As IAsyncResult)
            Dim data As String = ""
    
            Dim sb As New StringBuilder
            Dim buf(1024) As Byte
    
            Dim Escuchador As TcpListener
            Dim Cliente As TcpClient
            If Not Conectado Then Exit Sub
            Try
                Escuchador = CType(ar.AsyncState, TcpListener)
                Cliente = Escuchador.EndAcceptTcpClient(ar)
                Cliente.ReceiveTimeout = 5000
                IPRemota = Cliente.Client.RemoteEndPoint
                IPLocal = Cliente.Client.LocalEndPoint
    
            Catch ex As ObjectDisposedException
                MsgBox("Aceptar ObjectDisposedException " & ex.Message, MsgBoxStyle.Exclamation)
                Exit Sub
            End Try
    
            Try
                Dim stream As NetworkStream = Cliente.GetStream()
                Dim i As Int32
    
                i = stream.Read(buf, 0, buf.Length)
                While (i <> 0)
                    data = data & System.Text.Encoding.ASCII.GetString(buf, 0, i)
                    i = stream.Read(buf, 0, buf.Length)
    
                End While
                Cliente.Close()
    
                EstadoRecepcion = True
            Catch ex As TimeoutException
                MsgBox("doAcceptData timeout: " & ex.Message, MsgBoxStyle.Exclamation)
                EstadoRecepcion = False
                Cliente.Close()
                Exit Sub
            Catch ex As Exception
                MsgBox("doAcceptData: " & ex.Message, MsgBoxStyle.Exclamation)
                EstadoRecepcion = False
                Cliente.Close()
                Exit Sub
            Finally
                RaiseEvent RecepcionOk(EstadoRecepcion)
            End Try
            SincroContext.Post(New SendOrPostCallback(AddressOf RecibiendoDatos), data)
            Servidor.BeginAcceptTcpClient(New AsyncCallback(AddressOf Aceptar), Servidor)
        End Sub

    Thursday, April 26, 2018 7:06 PM