Delphi-使用Indy检查客户端状态的简单TCP客户端/服务器 [英] Delphi - Simple TCP client / server using Indy to check clients status

查看:215
本文介绍了Delphi-使用Indy检查客户端状态的简单TCP客户端/服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近开始使用Indy 10(来自Delphi XE3)和TCP连接。现在,我正在尝试创建一个简单的服务器应用程序以检查客户端状态。但是,当我尝试在已连接某些客户端的情况下停用TCPServer时,客户端确实会断开连接,但TCPServer会停止应答。

I started playing with Indy 10 (from Delphi XE3) and TCP connections recently. For now, I am trying to create a simple server application to check clients status. But when I try to deactivate TCPServer with some client already connected, clients do get disconnected but TCPServer stops answering.

我读到某处TCPServer应该可以处理客户端的断开连接而不会出现问题。我必须在OnExecute事件上添加一些代码来解决此问题吗?

I read somewhere that TCPServer should handle client's disconnection without problems. Must I add some code on OnExecute event to solve this problem?

这是代码:

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;

谢谢!

推荐答案

您在犯一些错误。


  1. 请勿实例化 TIdStack 类。当任何Indy套接字组件都处于活动状态时,Indy会为您实例化一个实例。如果需要访问套接字堆栈,请使用全局 GStack 对象指针,例如:

  1. DO NOT instantiate a TIdStack class directly. Indy instantiates one for you while any Indy socket component is alive. If you need to access the socket stack, use the global GStack object pointer, eg:

GStack.HostByAddress(AContext.Binding.PeerIP)

在极少数情况下,当您需要在没有Indy组件处于活动状态时访问 GStack 时,可以使用 TIdStack.IncUsage() TIdStack.DecUsage()方法调用,以确保 GStack 可用。

In the rare case when you need to access GStack when no Indy component is alive, you can wrap your code with TIdStack.IncUsage() and TIdStack.DecUsage() method calls to ensure GStack is available.

TIdTCPServer 是多线程组件。侦听套接字和客户端套接字在工作线程中运行。 OnConnect OnDisconnect OnExecute OnException OnListenException 事件在那些辅助线程的上下文中触发,而不在主UI线程的上下文中触发。因此,您必须与主线程进行同步,以便安全地访问VCL / FMX UI控件,否则会发生不良情况,包括死锁等。您可以使用Indy的 TIdSync (同步)或 TIdNotify 类(异步),也可以使用 TThread.Synchronize()(同步)或 TThread.Queue()(异步)方法,以便在与主线程同步时需要。或您选择的任何其他线程间同步机制。 VCL / FMX UI控件只能在主线程的上下文中访问。

TIdTCPServer is a multi-threaded component. Listening sockets and client sockets run in worker threads. The OnConnect, OnDisconnect, OnExecute, OnException, and OnListenException events are fired in the context of those worker threads, NOT in the context of the main UI thread. As such, you MUST synchronize with the main thread in order to access VCL/FMX UI controls safely, or else bad things happen, including deadlocks amongst other things. You can use Indy's TIdSync (synchronous) or TIdNotify class (asynchronous) class, or the static version of the TThread.Synchronize() (synchronous) or TThread.Queue() (asynchronous) method, to sync with the main thread when needed. Or any other inter-thread sync mechanism of your choosing. VCL/FMX UI controls MUST be accessed only in the context of the main thread.

警告:在停用 TIdTCPServer 从主线程开始,请勿使用同步同步,这是有保证的死锁。要么使用异步同步,要么从另一个线程(虽然不是服务器线程)停用服务器,以便主线程可以自由地正常处理同步。

A word of warning: while deactivating TIdTCPServer from the main thread, DO NOT use a synchronous sync, that is a guaranteed deadlock. Either use an asynchronous sync, or deactivate the server from another thread (not a server thread, though) so the main thread is free to process syncs normally.

Application.ProcessMessages()切勿在主UI线程之外调用。无需从 TIdTCPServer 事件中调用它。

Application.ProcessMessages() should never be called outside of the main UI thread. There is no need to ever call it from the TIdTCPServer events.

请尝试以下操作:

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;

这篇关于Delphi-使用Indy检查客户端状态的简单TCP客户端/服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆