gpt4 book ai didi

Delphi 和 Indy - 如何从 IdTCPServer 向特定的 IdTCPClient 发送内容

转载 作者:可可西里 更新时间:2023-11-01 02:40:57 31 4
gpt4 key购买 nike

我最近开始玩 Indy 10(来自 Delphi XE3)和 TCP 连接。在您的帮助下(特别感谢 Remy Lebeau),我已经可以构建一个简单的服务器应用程序来管理客户端连接(参见此处 Delphi - Simple TCP client / server using Indy to check clients status )。我正在使用列表框来添加连接的客户端。看代码:

procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
Procedure
begin
ListBox.Itens.Add(Host);
Log('Connected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;

现在我正尝试从服务器向列表中的特定客户端发送“hello”。我的想法是单击以在列表框中选择一个客户端主机名,然后单击一个按钮来发送消息。但是我正在研究的是,事情并没有我想的那么容易......

拜托,一些 Indy 专家可以给我指出正确的方向(使用 Indy 10)吗?

谢谢!

最佳答案

问候最常从 OnConnect 事件发送,您可以在该事件中直接访问已连接客户端的 TIdContext

话虽这么说,如果您想从服务器事件外部向特定客户端发送数据,那么您需要跟踪所需客户端的 TIdContext 对象,或者寻找它在服务器的 Contexts 列表中。在此特定示例中,您可以将 TIdContext 对象指针存储在 ListBox 本身中,然后在需要时检索它,例如:

procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
procedure
begin
ListBox.Items.AddObject(Host, AContext);
Log('Connected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;

procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
procedure
var
Index: Integer;
begin
Index := ListBox.Items.IndexOfObject(AContext);
if Index <> -1 then
ListBox.Items.Delete(Index);
Log('Disconnected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;

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;

诚然,这不是最安全的方法,但它可以帮助您入门。您需要考虑的事项:

  1. 客户端可能会在您将其从 ListBox 中删除之前断开连接并释放其 TIdContext 对象。在使用它之前,您应该确保该对象仍在服务器的 Contexts 列表中。

  2. 从按钮事件(或任何其他非服务器事件)发送未经请求的数据不是线程安全的。如果您从其他线程向同一个客户端发送数据,特别是从服务器的事件发送数据,而不同步线程,您的通信可能会被破坏。您应该仅在服务器事件中管理通信。如果您需要从事件外部发送数据,将数据放入每个客户端的线程安全队列中更安全,然后让 OnExecute 事件发送队列的内容。这样做是安全的。我之前在几个不同的论坛上多次发布过这样的例子,所以在网上应该不难找到它们。

  3. OnDisconnect 事件不是查找客户端详细信息(如其主机名)的好地方。您应该在 OnConnect 和/或 OnExecute 事件中执行此操作,然后缓存该值以备后用。为此,您可以使用 TIdContext.Data 属性,或者从 TIdServerContext 派生一个新类并在激活服务器之前设置服务器的 ContextClass 属性.

关于Delphi 和 Indy - 如何从 IdTCPServer 向特定的 IdTCPClient 发送内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27218701/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com