接收来自N个客户端的响应,以响应UDP上的广播请求

时间:2010-03-02 16:06:18

标签: c++ c sockets udp broadcast

我正在为特定类型的网络多媒体设备实现一种IP查找器。 我想找出局域网中所有这种类型的活动设备,包括它们的IP地址和其他细节。

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

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

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

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

  

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

我正在用C / C ++编程,计划为Windows和Linux编写代码 非常感谢提前。

编辑: 所以在这里所有网络编程向导的帮助下,我找到了解决问题的方法:) select()对我来说就是这个......
非常感谢所有花时间帮助我的人

4 个答案:

答案 0 :(得分: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()通常用于无连接模式套接字,因为它允许应用程序检索接收数据的源地址。

答案 1 :(得分:2)

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

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

无论如何,您可能必须处理设备注册时的超时,但稍后会失败。

答案 2 :(得分: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秒。根据底层协议的不同,您可以使用更短的超时时间;事实上,你可以减少每个回复。需要进行一些测试和调整才能找到最佳配置。您无需担心服务器同时响应;以太网层将处理它。

答案 3 :(得分:0)

你无法知道。它不可知。

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

如果我说得对,那UDP本质上是不可靠的,你将不得不在UDP之上改编一些可靠性:

  • 每隔几秒发送一次广播,因为设备可能不会每次都收到广播。
  • 您可能不会收到回复,但下次可能会收到回复。
  • 回复确认设备有效。
  • 在声明设备死机之前等待'n'无响应。

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