如何使用 Indy 组件从具有多个绑定的 IDTCPServer 套接字发送

How to use Indy component to Send from a IDTCPServer socket with Multiple Bindings

我希望在 TIdTCPServer 套接字组件上使用多个绑定来将数据发送到多个不同的客户端。我可以成功创建绑定并为每个绑定分配不同的端口号。这是我创建绑定的代码:

IdTCPServer1.Active := False;
IdTCPServer1.Bindings.Clear;
{create the new sockets}
for i := 0 to NumberOfItemsSpin.Value-1 do
begin
  IdTCPServer1.Bindings.Add;
  IdTCPServer1.Bindings.Items[i].Port := StartingPortSpin.Value+i;
end;
SocketsCreatedCount := IdTCPServer1.Bindings.Count;
Timer1.Enabled      := SocketsCreatedCount > 0;
IdTCPServer1.Active := True;

客户端知道要连接的 IP 地址和端口,并且能够成功连接。但是,我需要根据某些事件 异步 发送 数据到任何一个连接的客户端。

我知道我可以检测到 OnExecute 事件,获取 Context 并回复,但我的服务器套接字需要异步工作。它不会被客户端轮询。

我从连接信息中知道了客户端的 IP 地址和端口号。但是,我找不到将数据发送到特定客户端的方法。如何使用组件正确映射绑定并将数据发送到正确连接的客户端?

您似乎对 TIdTCPServer 的实际工作方式有一点误解。

Bindings合集与个别客户无关。 Binding 项只是服务器侦听连接的 IP/Port 对。 Binding 和客户端之间没有映射。当客户端连接时,为它创建一个 TIdContext 对象并存储在服务器的 Contexts 列表中,然后 OnConnect/OnDisconnect/OnExecute 事件是为 TIdContext 触发,独立于其他客户端。 TIdTCPserver 是多线程的,每个客户端 运行 在自己的专用线程中,给定客户端的事件在该客户端的线程内触发,因此多个客户端的事件可以 运行并发宁

OnExecute 事件不依赖于客户端轮询服务器。在客户端连接的生命周期内,事件只是在一个连续的循环中被调用。事件处理程序决定在每次循环迭代中如何处理客户端。但是,您需要分配一个处理程序,否则在服务器激活时会引发异常(为避免这种情况,您可以从 TIdTCPServer 派生一个新的 class 并覆盖其 CheckOkToBeActive() 方法不引发异常)。

要向任何特定客户端发送数据,只需在服务器的 Contexts 列表中找到该客户端的 TIdContext 对象,然后您就可以访问其关联的 TIdTCPConnection 对象进行交换与该客户的数据。

但是,从搜索 Contexts 列表的同一循环内部执行发送在继承上是不安全的,因此我建议您创建一个每个客户端的线程安全队列(例如 TIdThreadSafe(String|Object)List instance) 来保存您的出站数据,然后当您找到客户端时,您可以将数据放入该客户端的关联队列中。然后,您可以让 OnExecute 事件处理程序在客户端队列不为空时发送其客户端队列的内容。这样,您就可以避免客户端相互阻塞,错误处理针对每个客户端进行本地化,并且您可以并行向多个客户端发送数据。

要将队列与每个客户端相关联,您可以:

  • 使用publicTIdContext.Data属性.

  • TIdServerContext导出一个新的class,根据需要向其中添加您自己的自定义字段,然后将那个class分配给服务器的ContextClass 属性 在激活服务器之前。然后,您可以对任何 TIdContext 对象指针进行类型转换以访问您的自定义字段。

有关代码示例,请参阅 this answer 我发布到之前的问题:

How do I send a command to a single client instead of all of them?