Delphi - Indy TCPServer如何管理客户端连接?

时间:2014-12-13 16:23:08

标签: delphi tcp indy

我正在创建一个仅在Windows操作系统上运行的客户端 - 服务器应用程序,每个Windows用户将一次连接到服务器。 LAN使用DHCP,因此IP不固定。

我需要从IdTCPServer向特定的IdTCPClient发送一个字符串消息。一开始我使用的是Listbox,所以我在连接时将主机名添加到列表框中,并在断开连接时删除。那时,Remy Lebeau给了我这个小费:

procedure TfrmMain.sendButtonClick(Sender: TObject);
var
  Index: Integer;
  Ctx: TIdContext;
begin
  Index := ListBox.ItemIndex;
  if Index = -1 then Exit;
  Context := TIdContext(ListBox.Items.Objects[Index]);
  // use Context as needed...
end;

但现在我正在使用带有预先添加的主机名的ListView。所以我只是在客户端连接或断开连接时更改列表框项目图像状态。现在我正在尝试这样的事情:

procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
begin
  TThread.Queue(nil,
    procedure
    var
      Host: String;
      LItem: TListItem;
    begin
      Host := UpperCase(GStack.HostByAddress(Ctxt.Binding.PeerIP));
      LItem := lvwPCList.FindCaption(0, Host, False, True, False);
      if (LItem <> nil) then LItem.Data := AContext.Data;
    end
  );
end;

一旦我将Listview项目与Context数据相关联,我就会尝试将消息直接发送给客户端:

procedure TfrmMain.SendMessage(const Item: TListItem; const Msg: String);
var
  Ctx: TIdContext;
begin
  if (Trim(Msg) = '') then Exit;
  Ctx := TIdContext(Item.Data);
  try
    Ctx.Connection.IOHandler.WriteLn(Msg);
  except
  end;
end;

我可以编译此代码,但消息永远不会到达客户端。请问,我做错了什么?

谢谢!

1 个答案:

答案 0 :(得分:1)

您应该在TIdContext继承中实现唯一的会话ID。在每个新连接上生成新的唯一ID。例如,您可以使用递增的整数,或生成GUID。在任何情况下,您都有自己唯一的“会话ID”,它唯一地标识客户端/服务器“会话”。这假设您希望完成某种会话管理。

至于循环,您仍然需要执行循环来查找相应的客户端。但是这样的循环是微不足道的,并且可以在几分之一毫秒内执行,即使有数千个连接的客户端(已经在任何服务器上进行了大修)。即使你依赖内置的东西,内置函数仍然会执行一个循环。

您不能简单地通过其主机名或IP地址引用已连接的客户端,因为同一客户端可能有多个连接。由于这一事实,没有“通过主机或IP向客户端发送消息”这样的事情。您需要明确引用特定连接。不要担心您的连接是否来自同一台计算机/设备,除非您打算严格禁止来自同一设备的多个连接但即便如此,如果您决定通过互联网使用此连接,则所有客户端背后相同的网络将被视为相同的IP。这同样适用于除Windows以外的其他设备。在将来,您可能希望支持其他设备,如果您计划在某一天走这条路线,您需要确保您的结构已经准备就绪。