如何使用 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?
我希望在 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
事件处理程序在客户端队列不为空时发送其客户端队列的内容。这样,您就可以避免客户端相互阻塞,错误处理针对每个客户端进行本地化,并且您可以并行向多个客户端发送数据。
要将队列与每个客户端相关联,您可以:
使用public
TIdContext.Data
属性.从
TIdServerContext
导出一个新的class,根据需要向其中添加您自己的自定义字段,然后将那个class分配给服务器的ContextClass
属性 在激活服务器之前。然后,您可以对任何TIdContext
对象指针进行类型转换以访问您的自定义字段。
有关代码示例,请参阅 this answer 我发布到之前的问题:
How do I send a command to a single client instead of all of them?