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

时间:2017-04-21 23:31:13

标签: delphi indy

我希望在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地址和端口号。但是,我找不到将数据发送到特定客户端的方法。如何使用组件正确映射绑定并将数据发送到正确的连接客户端?

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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

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

  • 使用公共OnExecute属性。

  • TIdContext.Data派生一个新类,根据需要为其添加自己的自定义字段,然后在激活服务器之前将该​​类分配给服务器的TIdServerContext属性。然后,您可以键入任何ContextClass对象指针以访问自定义字段。

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

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