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")
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.