Search code examples
tcpindy10delphi-10.1-berlin

How can I listening "controller board" with indy 10 tcpip?


I have a code in Visual Basic, that have a timer and listening a tcpip stream. I´m try to code it in deplhi, but I have problems.

I get connect sucessful in board with tcpip like this : IdTCPClient1.Connect;

Board tcpip is 192.168.0.180, port 2000, my server is 192.168.0.30.

I´m try this code :

procedure TForm1.Button8Click(Sender: TObject);
var StrStream: TMemoryStream;
begin

  if IdTCPClient1.Connected then
    begin
      StrStream := TMemoryStream.Create;
      if IdTCPClient1.IOHandler.Connected then
        IdTCPClient1.IOHandler.ReadStream(StrStream,-1,false);

      Memo1.Lines.Add('hello');
    end;

end;

The problem is, in line IdTCPClient1.IOHandler.ReadStream(StrStream,-1,false); the application stop, no error, no message and I don´t undestand.

VB code

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick

        Try

            If tcp1.Available > 1 Then
                Dim leitura As NetworkStream = tcp1.GetStream
                Dim bytes(tcp1.ReceiveBufferSize) As Byte
                leitura.Read(bytes, 0, CInt(tcp1.ReceiveBufferSize))
                returndata = Encoding.ASCII.GetString(bytes)
                txtSerial1.AppendText(returndata)

            End If

            If tcp2.Available > 1 Then
                Dim leitura As NetworkStream = tcp2.GetStream
                Dim bytes(tcp2.ReceiveBufferSize) As Byte
                leitura.Read(bytes, 0, CInt(tcp2.ReceiveBufferSize))
                returndata = Encoding.ASCII.GetString(bytes)
                txtSerial2.AppendText(returndata)
            End If


        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

Solution

  • When calling the IOHandler's ReadStream() method, setting AByteCount=-1 and AReadUntilDisconnect=False as you are tells ReadStream() to expect the incoming data to be preceded by a multi-byte integer (either 4 or 8 bytes, depending on the IOHandler's LargeStream property) that specifies the number of subsequent bytes in the data, and it then waits for that many bytes to actually arrive. Is that what the server's data actually looks like? I doubt it, because that is not what your VB code is expecting.

    Using the IOHandler's ReadBytes() method with AByteCount=-1 would be a closer equivalent to your VB code than using the ReadStream() method, eg:

    procedure TForm1.Button8Click(Sender: TObject);
    var
      Bytes: TIdBytes;
    begin
      if IdTCPClient1.Connected then
      begin
        IdTCPClient1.IOHandler.ReadBytes(Bytes, -1);
        // use Bytes as needed...
        Memo1.Lines.Add('hello');
      end;
    end;
    

    Also, keep in mind that Indy uses blocking socket I/O by default. You really shouldn't perform blocking operations in the main UI thread. You should move your reading logic to a separate worker thread instead. Or, at the very least, make sure you set a small ReadTimeout on the TIdTCPClient so ReadBytes() does not block the UI for very long.