Delphi 在工作线程中断开 TIdTCPClient
Delphi disconnecting TIdTCPClient in worker thread
我需要通过 FMX 应用程序向设备发送 TCP 字节数组。我有这个界面:
type
IPacketSend = interface
procedure SendAsync(const Msg: String; OnSuccess: TSendSuccess; OnError: TSendError);
end;
我必须使用线程来不阻塞 UI。 class 实际上以非常简化的版本发送消息:
type
TPacketSenderLAN = class(TInterfacedObject, IPacketSend)
private
FSelf: IPacketSend;
public
procedure SendAsync(const Msg: String; OnSuccess: TSendSuccess; OnError: TSendError);
end;
implementation
{ TPacketSender<T> }
procedure TPacketSenderLAN.SendAsync(const Msg: String; OnSuccess: TSendSuccess;
OnError: TSendError);
begin
TTask.Run(
procedure
var
Client: TIdTCPClient;
Exc: TObject;
begin
Client := TIdTCPClient.Create(nil);
try
try
Client.Host := '192.168.0.213';
Client.Port := 5200;
Client.ConnectTimeout := 3500;
Client.Connect;
Data := TIdBytes(...);
Client.Socket.Write(Data);
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
FSelf := nil;
end
);
except
on E: Exception do
begin
Exc := AcquireExceptionObject;
TThread.Synchronize(nil,
procedure
begin
OnError(Exception(exc).Message);
FSelf := nil;
end
);
end;
end;
finally
Client.Free;
end;
end
);
end;
end.
FSelf
变量是绝对需要的,因为在构造函数中使用 FSelf := Self;
我可以防止工作线程执行时引用计数变为 0。其实我叫...
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
FSelf := nil;
end
);
... 其中 FSelf := nil;
位于末尾,以便在作业完成后处理该对象。我从代码中这样调用它:
var
PacketSender: IPacketSend;
begin
PacketSender := TPacketSenderLAN.Create(...);
end;
鉴于上述情况,我的问题是:
am I using the TIdTCPClient safely? Do I have to disconnect it?
我不知道是否应该在 finally 块中调用 Client.Disconnect;
。我认为不需要,因为 Free 会破坏 TIdTCPClient
,因此客户端会断开连接。我的代码安全吗?
am I using the TIdTCPClient safely?
是的,你是。
Data
,另一方面,不是那么多,因为它没有显示为局部变量,甚至不是 TPacketSenderLAN
class 的成员,这意味着它必须是一个全局变量,因此会受到多线程并发问题的影响。在这种情况下,它应该是一个局部变量。
Do I have to disconnect it?
我会推荐它,是的,特别是在调用您的 OnSuccess
/OnError
处理程序之前。如果不手动调用Disconnect()
,则TCP连接不会断开,直到调用TIdTCPClient
析构函数。在此代码中,当您的事件处理程序 运行 时,TCP 连接没有理由保持活动状态。
I don't know if I should call Client.Disconnect;
inside the finally
block.
我实际上建议添加 另一个 try..finally
块只是为了调用 Disconnect()
,例如:
procedure
var
Client: TIdTCPClient;
Data: TIdBytes;
begin
try
Client := TIdTCPClient.Create(nil);
try
Client.Host := '192.168.0.213';
Client.Port := 5200;
Client.ConnectTimeout := 3500;
Client.Connect;
try
Data := TIdBytes(...);
Client.IOHandler.Write(Data);
finally
Client.Disconnect;
end;
finally
Client.Free;
end;
except
on E: Exception do
begin
TThread.Synchronize(nil,
procedure
begin
OnError(E.Message);
end
);
Exit;
end;
end;
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
end
);
end
我需要通过 FMX 应用程序向设备发送 TCP 字节数组。我有这个界面:
type
IPacketSend = interface
procedure SendAsync(const Msg: String; OnSuccess: TSendSuccess; OnError: TSendError);
end;
我必须使用线程来不阻塞 UI。 class 实际上以非常简化的版本发送消息:
type
TPacketSenderLAN = class(TInterfacedObject, IPacketSend)
private
FSelf: IPacketSend;
public
procedure SendAsync(const Msg: String; OnSuccess: TSendSuccess; OnError: TSendError);
end;
implementation
{ TPacketSender<T> }
procedure TPacketSenderLAN.SendAsync(const Msg: String; OnSuccess: TSendSuccess;
OnError: TSendError);
begin
TTask.Run(
procedure
var
Client: TIdTCPClient;
Exc: TObject;
begin
Client := TIdTCPClient.Create(nil);
try
try
Client.Host := '192.168.0.213';
Client.Port := 5200;
Client.ConnectTimeout := 3500;
Client.Connect;
Data := TIdBytes(...);
Client.Socket.Write(Data);
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
FSelf := nil;
end
);
except
on E: Exception do
begin
Exc := AcquireExceptionObject;
TThread.Synchronize(nil,
procedure
begin
OnError(Exception(exc).Message);
FSelf := nil;
end
);
end;
end;
finally
Client.Free;
end;
end
);
end;
end.
FSelf
变量是绝对需要的,因为在构造函数中使用 FSelf := Self;
我可以防止工作线程执行时引用计数变为 0。其实我叫...
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
FSelf := nil;
end
);
... 其中 FSelf := nil;
位于末尾,以便在作业完成后处理该对象。我从代码中这样调用它:
var
PacketSender: IPacketSend;
begin
PacketSender := TPacketSenderLAN.Create(...);
end;
鉴于上述情况,我的问题是:
am I using the TIdTCPClient safely? Do I have to disconnect it?
我不知道是否应该在 finally 块中调用 Client.Disconnect;
。我认为不需要,因为 Free 会破坏 TIdTCPClient
,因此客户端会断开连接。我的代码安全吗?
am I using the TIdTCPClient safely?
是的,你是。
Data
,另一方面,不是那么多,因为它没有显示为局部变量,甚至不是 TPacketSenderLAN
class 的成员,这意味着它必须是一个全局变量,因此会受到多线程并发问题的影响。在这种情况下,它应该是一个局部变量。
Do I have to disconnect it?
我会推荐它,是的,特别是在调用您的 OnSuccess
/OnError
处理程序之前。如果不手动调用Disconnect()
,则TCP连接不会断开,直到调用TIdTCPClient
析构函数。在此代码中,当您的事件处理程序 运行 时,TCP 连接没有理由保持活动状态。
I don't know if I should call
Client.Disconnect;
inside thefinally
block.
我实际上建议添加 另一个 try..finally
块只是为了调用 Disconnect()
,例如:
procedure
var
Client: TIdTCPClient;
Data: TIdBytes;
begin
try
Client := TIdTCPClient.Create(nil);
try
Client.Host := '192.168.0.213';
Client.Port := 5200;
Client.ConnectTimeout := 3500;
Client.Connect;
try
Data := TIdBytes(...);
Client.IOHandler.Write(Data);
finally
Client.Disconnect;
end;
finally
Client.Free;
end;
except
on E: Exception do
begin
TThread.Synchronize(nil,
procedure
begin
OnError(E.Message);
end
);
Exit;
end;
end;
TThread.Synchronize(nil,
procedure
begin
OnSuccess;
end
);
end