Search code examples
delphidebuggingtcpfiremonkeyindy10

Indy TCPServer is giving `Connection reset by peer` error when client connects


I am trying to create a TCP server using Delphi firemonkey application.

My resource file Unit1.fmx is given below.

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnActivate = FormShow
  OnCreate = FormCreate
  DesignerMasterStyle = 0
  object Label1: TLabel
    Position.X = 504.000000000000000000
    Position.Y = 248.000000000000000000
    Text = 'Label1'
  end
  object TCPServer: TIdTCPServer
    Bindings = <>
    DefaultPort = 0
    OnAfterBind = TCPServerAfterBind
    OnConnect = TCPServerOnConnect
    OnExecute = TCPserverExecute
    Left = 560
    Top = 184
  end
end

My code file is given here.

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Platform,
  IdCustomTCPServer, IdTCPServer, IdBaseComponent, IdComponent, IdUDPBase, IdContext,
  IdSocketHandle, IdUDPServer, FMX.Controls.Presentation, FMX.StdCtrls, Windows;

type
  TForm1 = class(TForm)
    TCPServer: TIdTCPServer;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure TCPserverExecute(AContext: TIdContext);
    procedure TCPServerOnConnect(AContext: TIdContext);
    procedure TCPServerAfterBind(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyLoggingService = class(TInterfacedObject, IFMXLoggingService)
  public
    procedure Log(const Format: string; const Params: array of const);
  end;

var
  Form1: TForm1;
  MyLoggingService: IFMXLoggingService;

implementation

{$R *.fmx}

procedure TMyLoggingService.Log(const Format: string; const Params: array of const);
begin
  // do whatever you want...
  OutputDebugString(PChar(Format));
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  Binding : TIdSocketHandle;
begin
  MyLoggingService := TMyLoggingService.Create;
  if TPlatformServices.Current.SupportsPlatformService( IFMXLoggingService ) then
    TPlatformServices.Current.RemovePlatformService( IFMXLoggingService );
  // register my service
  TPlatformServices.Current.AddPlatformService( IFMXLoggingService, MyLoggingService );
  TCPServer.DefaultPort := 16000;
  TCPServer.Bindings.Clear;
  Binding := TCPServer.Bindings.Add;
  Binding.IP := '127.0.0.1';
  Binding.Port := 16000;
  //if Assigned(MyLoggingService) then
  MyLoggingService.Log('FormCreate!',[]);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
 TCPServer.Active := True;
end;

procedure TForm1.TCPServerAfterBind(Sender: TObject);
begin
  MyLoggingService.Log('After Bind',[]);
end;

procedure TForm1.TCPServerOnConnect(AContext: TIdContext);
begin
  MyLoggingService.Log('Recieved Connection From Client ',[]);
end;

procedure TForm1.TCPServerExecute(AContext: TIdContext);
Var
C : String;
begin
 C:= AContext.Connection.Socket.ReadLn();
 //if Assigned(MyLoggingService) then
 MyLoggingService.Log('TserverExecute !',[]);

 MyLoggingService.Log('Recived Data !',[C]);
 if C = 'TESTSTRING' then
 begin
   AContext.Connection.Socket.Writeln('SENT');
 end;


end;

end.

My problem is In the system log where I am logging my messages this is what I get.

Debug Output: FormCreate! Process Project1.exe (3340)
Debug Output: After Bind Process Project1.exe (3340)
Debug Output: Recieved Connection From Client  Process Project1.exe (3340)
First chance exception at $759BC42D. Exception class EIdSocketError with message
'Socket Error # 10054
Connection reset by peer.'.
Process Project1.exe (3340)

connection reset by peer. My question is why is this happening with my code ? What am I doing wrong and what can I do to fix it?

At the remote end I have a very simple python script which is given below.

import socket

# Set up a TCP/IP socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# Connect as client to a selected server
# on a specified port
s.connect(('127.0.0.1',16000))

# Protocol exchange - sends and receives
data = 'TESTSTRING';
s.send(data.encode())
while True:
    resp = s.recv(1024)
    if resp == "": 
        print('NOTHING')
        break
    else:
        print(resp)
        break

# Close the connection when completed
s.close()
print("\ndone")

Solution

  • There is nothing wrong with the server code. The client is disconnecting on its end, and the debugger on the server side is simply detecting the exception that Indy raises to itself to handle the disconnect. This is normal behavior.

    There is, however, a problem with your client code. On the server side, you are using TIdIOHandler.ReadLn(), which is expecting the client to send a line of text delimited by a LF character (or a CRLF string). But your client script is not sending that delimiter at all, so ReadLn() does not exit, and the server consequently does not call TIdIOHandler.WriteLn() to send a response. On the client side, s.recv() is likely failing (since no response is being received) and the script ends, disconnecting the socket, causing ReadLn() on the server side to raise an exception back to TIdTCPServer so it can stop the thread close the socket.