我最近开始使用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)
在极少数情况下,GStack
当没有Indy组件处于活动状态时需要访问时,可以使用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
从主线程取消激活时,请勿使用同步同步,这是有保证的死锁。使用异步同步,或从另一个线程(尽管不是服务器线程)停用服务器,以便主线程可以自由地正常处理同步。
Application.ProcessMessages()
切勿在主UI线程之外调用它。无需从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;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句