2017-04-21 32 views
0

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

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

回答

3

您好像对TIdTCPServer的实际工作原理有一点误解。

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

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

要发送数据到任何特定的客户端,只需找到该客户的TIdContext服务器的Contexts列表中的对象,那么你将有机会获得其相关TIdTCPConnection对象与客户端进行数据交换。

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

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

  • 使用公共TIdContext.Data财产。

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

有关代码示例,请参阅this answer我贴到前面一个问题:

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

相关问题