[英]Delphi - Simple TCP client / server using Indy to check clients status
我最近开始使用Indy 10(来自Delphi XE3)和TCP连接。 现在,我正在尝试创建一个简单的服务器应用程序以检查客户端状态。 但是,当我尝试在已连接某些客户端的情况下停用TCPServer时,客户端确实会断开连接,但TCPServer会停止应答。
我读过某个地方,TCPServer应该可以毫无问题地处理客户端的断开连接。 我必须在OnExecute事件上添加一些代码来解决此问题吗?
这是代码:
procedure TfrmMain.btnConnectClick(Sender: TObject);
begin
If (not TCPServer.Active) Then
Try
TCPServer.Bindings.Clear;
With TCPServer.Bindings.Add Do
Begin
IP := '192.168.1.11';
Port := StrToInt(edtPort.Text);
end;
TCPServer.Active := True;
Except
On E:Exception Do ShowMessage(E.Message);
End
end;
procedure TfrmMain.btnDisconnectClick(Sender: TObject);
begin
If (TCPServer.Active) Then
Try
TCPServer.Active := False;
Except
On E:Exception Do ShowMessage(E.Message);
End
end;
procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
IdStackWin: TIdStackWindows;
begin
IdStackWin := TIdStackWindows.Create;
With IdStackWin Do
Try
memLog.Lines.Add('Connected - ' + HostByAddress(AContext.Binding.PeerIP) + ' (' + AContext.Binding.PeerIP + ')');
Finally
IdStackWin.Free;
end;
end;
procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
IdStackWin: TIdStackWindows;
begin
IdStackWin := TIdStackWindows.Create;
With IdStackWin Do
Try
memLog.Lines.Add('Disconnected - ' + HostByAddress(AContext.Binding.PeerIP) + ' (' + AContext.Binding.PeerIP + ')');
Finally
IdStackWin.Free;
end;
end;
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
begin
Application.ProcessMessages;
end;
谢谢!
您正在犯一些错误。
不要直接实例化TIdStack
类。 当任何Indy套接字组件都处于活动状态时,Indy会为您实例化一个实例。 如果需要访问套接字堆栈,请使用全局GStack
对象指针,例如:
GStack.HostByAddress(AContext.Binding.PeerIP)
在极少数情况下,当没有Indy组件GStack
时需要访问GStack
时,可以使用TIdStack.IncUsage()
和TIdStack.DecUsage()
方法调用包装代码,以确保GStack
可用。
TIdTCPServer
是一个多线程组件。 侦听套接字和客户端套接字在工作线程中运行。 OnConnect
, OnDisconnect
, OnExecute
, OnException
和OnListenException
事件是在那些辅助线程的上下文中触发的,而不是在主UI线程的上下文中触发的。 因此,您必须与主线程进行同步,以便安全地访问VCL / FMX UI控件,否则会发生不良情况,包括死锁等。 您可以使用Indy的TIdSync
(同步)或TIdNotify
类(异步)类,或TThread.Synchronize()
(同步)或TThread.Queue()
(异步)方法的静态版本在需要时与主线程同步。 或您选择的任何其他线程间同步机制。 VCL / FMX UI控件必须仅在主线程的上下文中访问。
警告:从主线程禁用TIdTCPServer
,请勿使用同步同步,这是有保证的死锁。 您可以使用异步同步,也可以从另一个线程(虽然不是服务器线程)停用服务器,以便主线程可以自由地正常处理同步。
绝对不应在主UI线程之外调用Application.ProcessMessages()
。 无需从TIdTCPServer
事件中调用它。
尝试以下方法:
procedure TfrmMain.btnConnectClick(Sender: TObject);
begin
if not TCPServer.Active then
begin
TCPServer.Bindings.Clear;
with TCPServer.Bindings.Add do
Begin
IP := '192.168.1.11';
Port := StrToInt(edtPort.Text);
end;
TCPServer.Active := True;
end;
end;
procedure TfrmMain.btnDisconnectClick(Sender: TObject);
begin
TCPServer.Active := False;
end;
procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Msg: string;
begin
Msg := 'Connected - ' + GStack.HostByAddress(AContext.Binding.PeerIP) + ' (' + AContext.Binding.PeerIP + ')';
TThread.Queue(nil,
procedure
begin
memLog.Lines.Add(Msg);
end
);
end;
procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
Msg: string;
begin
Msg := 'Disconnected - ' + GStack.HostByAddress(AContext.Binding.PeerIP) + ' (' + AContext.Binding.PeerIP + ')';
TThread.Queue(nil,
procedure
begin
memLog.Lines.Add(Msg);
end
);
end;
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
begin
// your communications logic here
end;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.