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