如何使用Indy10 TIdUDPClient接收广播数据包?

3

我正在连接一个发送UDP数据包的系统,这些数据包既可以作为响应(发送到特定的IP地址),也可以作为广播(目标地址为255.255.255.255,根据WireShark)。

我可以正确地接收“直接”的数据包,但我不知道如何获取广播数据包。我猜想我需要一个具有不同绑定的第二个TIdUDPClient,但我一直无法使其正常工作。

TIdUDPClient *reader(new TIdUDPClient(NULL));
TIdUDPClient *broadcastReader(new TIdUDPClient(NULL));

reader->Port = 2000;
reader->Host = "192.168.0.1";
reader->Connect();

broadcastReader->Port = 2000;
// broadcastReader->Host = "0.0.0.0"; // This doesn't work, but is here as an example
broadcastReader->BroadcastEnabled = true;
broadcastReader->Connect();

我有其他几个近乎相同的线程调用reader/broadcastReader->ReceiveBuffer()。其中reader是正常工作的,但broadcastReader->receiveBuffer()从未返回......对于C++代码和Delphi标签,我表示歉意;-)

如果目标是接收未经请求的数据包,那么你不需要一个客户端,而是需要一个服务器组件吗? - Rob Kennedy
@RobKennedy - 看起来是这样 - 不过,我只对接收来自特定主机IP的广播感兴趣。但在像UDP这样的无连接协议中,客户端和服务器之间的区别似乎有点奇怪。 - Roddy
1个回答

6

TIdUDPClient 不适用于接收广播。请使用 TIdUDPServer


TIdUDPClient并非完全无法接收广播。只是它无法像TIdUDPServer一样自动化接收过程。TIdUDPServer拥有一个名为OnUDPRead的事件,当新数据到达时触发该事件。要实现相同的功能,您需要手动调用TIdUDPClient.Receive...()方法之一,例如在定时器或线程中。但是,在处理广播数据时,您真的不应该使用Connect()函数。因为Connect()会在IP/端口对之间建立一个静态链接,这可能会在操作系统层面过滤掉广播数据包。 - Remy Lebeau
我已经从两个客户端切换到一个服务器,并让Indy管理监听线程。它运行良好,我的代码也更简单了。可能是connect()引起的问题,但我对新解决方案感到满意。 - Roddy
TIdUDPServer 不支持任何类型的过滤,所以您需要在每个数据包上手动查看发送者 IP。您可以在激活服务器之前设置每个 TIdUDPServer.Bindings 条目的 TIdSocketHandle.PeerIP 属性,然后使用 TIdUDPServer.OnAfterBind 事件在之后调用每个条目的 TIdSocketHandle.Connect(),但我不知道这是否有效,因为我从未尝试过。 - Remy Lebeau
这将是一个竞态条件,因为OnUDPRead事件会更新TIdSocketHandle.PeerIP属性,所以如果在您调用Connect()之前来自不需要的对等方的数据到达,您可能会最终过滤错误的对等方。 - Remy Lebeau
TIdUDPServer.Bindings 集合中的每个条目都有一个线程。如果多个对等方将数据包发送到您的服务器的相同IP/端口,则这些数据包将在 OnUDPRead 事件中进行序列化,因为只有一个线程会一次从网络中读取它们一个数据包。 - Remy Lebeau
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接