当客户端连接时,Indy TCPServer 给出“Connection reset by peer”错误
Indy TCPServer is giving `Connection reset by peer` error when client connects
我正在尝试使用 Delphi firemonkey 应用程序创建 TCP 服务器。
我的资源文件Unit1.fmx
如下。
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
我的代码文件在这里。
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.
我的问题是在我记录消息的系统日志中,这是我得到的。
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 9BC42D. Exception class EIdSocketError with message
'Socket Error # 10054
Connection reset by peer.'.
Process Project1.exe (3340)
connection reset by peer。我的问题是为什么我的代码会发生这种情况?我做错了什么,我该如何解决?
在远程端,我有一个非常简单的 python 脚本,如下所示。
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")
服务器代码没有问题。客户端在其端断开连接,服务器端的 调试器 只是检测 Indy 引发的异常以处理断开连接。 这是正常行为。
但是,您的客户端代码存在问题。在服务器端,您正在使用 TIdIOHandler.ReadLn()
,它期望客户端发送一行由 LF
字符(或 CRLF
字符串)分隔的文本。但是您的客户端脚本根本没有发送该分隔符,因此 ReadLn()
不会退出,因此服务器不会调用 TIdIOHandler.WriteLn()
来发送响应。在客户端,s.recv()
可能会失败(因为没有收到响应)并且脚本结束,断开套接字,导致服务器端的 ReadLn()
将异常返回到 TIdTCPServer
所以它可以停止线程关闭套接字。
我正在尝试使用 Delphi firemonkey 应用程序创建 TCP 服务器。
我的资源文件Unit1.fmx
如下。
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
我的代码文件在这里。
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.
我的问题是在我记录消息的系统日志中,这是我得到的。
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 9BC42D. Exception class EIdSocketError with message
'Socket Error # 10054
Connection reset by peer.'.
Process Project1.exe (3340)
connection reset by peer。我的问题是为什么我的代码会发生这种情况?我做错了什么,我该如何解决?
在远程端,我有一个非常简单的 python 脚本,如下所示。
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")
服务器代码没有问题。客户端在其端断开连接,服务器端的 调试器 只是检测 Indy 引发的异常以处理断开连接。 这是正常行为。
但是,您的客户端代码存在问题。在服务器端,您正在使用 TIdIOHandler.ReadLn()
,它期望客户端发送一行由 LF
字符(或 CRLF
字符串)分隔的文本。但是您的客户端脚本根本没有发送该分隔符,因此 ReadLn()
不会退出,因此服务器不会调用 TIdIOHandler.WriteLn()
来发送响应。在客户端,s.recv()
可能会失败(因为没有收到响应)并且脚本结束,断开套接字,导致服务器端的 ReadLn()
将异常返回到 TIdTCPServer
所以它可以停止线程关闭套接字。