6

我正在为特定类型的网络多媒体设备实现一种 IP 查找器。我想找出 LAN 中所有该类型的活动设备,以及它们的 IP 地址和其他详细信息。

设备有自己的设备发现方式。

它的工作原理如下:客户端通过 UDP 在 LAN 上发送广播请求。
目的端口号是固定的。
作为回应,LAN 中所有了解此请求格式的服务器都会响应此请求,提供有关它们自己的信息。

我正在使用 sendto() 广播 UDP 请求消息。

现在我的问题是我不知道有多少设备(即服务器)会响应请求。

我必须调用 recvfrom() 多少次?
我什么时候才能知道我已经处理了所有设备的响应?
或者一般来说,recvfrom() 是从多个服务器接收响应的正确选择吗?
有没有更好的(或正确的,如果我在这里错了)方法来完成同样的事情?

我正在使用 C/C++ 编程,计划同时为 Windows 和 Linux 编写代码。
提前谢谢了。

编辑:因此,在所有网络编程向导的帮助下,我找到了解决问题的方法 :)
select() 对我来说就是这样……
非常感谢所有抽出时间提供帮助的人我

4

4 回答 4

2

我必须调用 recvfrom() 多少次?我什么时候才能知道我已经处理了所有设备/服务器的响应?

如果您不知道设备/服务器的数量,您将无法知道需要调用多少次recvfrom()或何时处理了所有响应。

您可以考虑使用select()循环(直到超时)并recvfrom()在数据可供读取时调用。这可能在主线程或单独的线程中。

如果数据到达的速度快于处理速度,您将丢失数据报。这在很大程度上取决于数据在接收后被解析和存储的速度。如果处理数据是一项密集操作,则可能需要在单独的线程中进行处理或存储数据,直到接收循环超时,然后继续处理它。

由于 UDP 不可靠,循环重播几次应该有助于解决一些损失,并且处理应该解决重复问题。

以下伪代码是我解决问题的方法:


/* get socket to receive responses */
sd = socket( ... );

do
{
    /* set receive timeout */
    timeout.tv_sec = 5;     

    /* broadcast request */
    sendto( ... );

    /* wait for responses (or timeout) */
    while(select(sd+1, &readfds, NULL, NULL, &timeout) > 0)
    {
        /* receive the response */
        recvfrom( ... );

        /* process the response (or queue for another thread / later processing) */
        ...

        /* reset receive timeout */
        timeout.tv_sec = 5; 
    }

    /* process any response queued for later (and not another thread) */

} while (necessary);

或者一般来说,recvfrom() 是从多个服务器接收响应的正确选择吗?

recvfrom()通常与无连接模式套接字一起使用,因为它允许应用程序检索接收数据的源地址。

于 2010-03-02T16:15:07.890 回答
2

在循环中使用select(2)/poll(2)带有超时的 a,每次从设备获得响应时都会减少超时。你必须自己想出适当的超时时间。

或者,如果您能够识别/解析发现响应消息,只需在收到此类消息后将设备添加到列表中。

无论如何,当设备注册但稍后失败时,您可能不得不处理超时。

于 2010-03-02T16:49:05.537 回答
2

如果您不知道有多少服务器将响应,那么您就不知道您必须调用多少次 recvfrom()。我可能会使用一个带有适当超时的 select() 循环来处理这个问题,如下所示,它完全未经测试,可能充满了愚蠢的错误:

/* create and bind socket */

fd_set fds;
struct timeval tv;

tv.tv_sec = 2; 
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock, &fds);
int ret;

while((ret = select(sock + 1, &fds, NULL, NULL, &tv)) > 0) {
    char buf[BUFLEN];
    struct sockaddr addr;

    if(recvfrom(sock, buf, BUFLEN, MSG_DONTWAIT, &addr, sizeof(struct sockaddr)) > 0) {
        /* handle response */
    } else {
        /* handle error */
    }        
}
if(ret < 0) {
    /* handle error */
} else {
    /* select() timed out; we're theoretically done */
}

这将继续调用 recvfrom() 直到 2 秒内没有收到任何回复,这当然意味着它将阻塞至少 2 秒。根据底层协议,您可能会以更短的超时时间逃脱;实际上,您可以在每个响应中减少它。需要进行一些测试和调整才能找到最佳配置。您无需担心服务器同时响应;以太网层将处理这个问题。

于 2010-03-02T16:52:25.793 回答
0

你不能知道。其不可知。

据推测,根据您的描述:I want to find out all the alive devices,设备可以随时从死状态转换为活跃状态,然后再返回。这意味着您将不得不连续轮询:即每隔几秒钟(但不要太频繁)发送一次广播请求并查看谁响应。

如果我做对了,那么 UDP 本质上是不可靠的,那么您将不得不在 UDP 之上改进一些可靠性:

  • 每隔几秒钟发送一次广播,因为设备可能不会每次都收到它。
  • 您可能不会收到他们的回复,但下次您可能会收到。
  • 回复确认设备处于活动状态。
  • 在宣布设备死亡之前等待“n”个无响应。

您知道可能的设备的最大数量吗?如果你这样做,你可能会发现你必须多次调用 recvfrom() 。

于 2010-03-02T19:14:29.920 回答