代码之家  ›  专栏  ›  技术社区  ›  poundifdef

连续调用recvfrom()会丢失数据吗?

  •  7
  • poundifdef  · 技术社区  · 15 年前

    我正在开发一个使用UDP的可靠文件传输程序。(计算机网络课程。)

    我的问题是——好吧,考虑一下这个场景:

    1. 发送方(例如)有12个字节的数据要发送。因此发送方执行此调用:

      sendto(fd, &buf, 12, 0, (struct sockaddr *)&cliaddr,sizeof(cliaddr));
      

      这会以不可靠的方式发送12字节的数据。这个数据的前4个字节恰好是一个“消息长度”字段。在这种情况下,前4个字节的值可能为0x000000C。

    2. 接收器希望使用recvFrom()读取前4个字节。由于段大小为12个字节,所以它希望读取剩余的8个字节。所以接收器可能看起来像这样:

      /* read the segment size */
      recvfrom(sockfd,&buf,4,0,(struct sockaddr *)&cliaddr,&len);
      
      /* do some arithmetic, use bzero(), etc */
      
      /* read the rest of the data */
      recvfrom(sockfd,&buf,8,0,(struct sockaddr *)&cliaddr,&len);
      

    当我执行这段代码时,我可以毫无问题地接收前4个字节。但当我试图获取剩余的数据时,这些数据似乎丢失了。在我的输出中,我得到了垃圾-它看起来像 下一个 发送方被发送到的12个字节。

    这是预期行为吗?也就是说,如果一个recvfrom()调用不能读取所有发送的数据,是否不能保证数据(剩余的8字节)对我可用?

    似乎发送段头(包括其大小)和有效负载的标准方法不起作用。这是否意味着我需要发送两个单独的段-一个只包含头信息,然后是第二个带有效载荷的段?或者我只是不正确地使用这些系统调用(或者是否有我缺少的标志或setsockopt())

    2 回复  |  直到 15 年前
        1
  •  8
  •   camh    15 年前

    从Recv(2)手册页:

    如果邮件太长,无法放入 提供的缓冲区,多余的字节可以是 根据类型丢弃 接收消息的套接字。

    这就是发生在你身上的事情。

    您应该有一个最大消息大小的缓冲区,并读取该大小。您将只读取一个数据报,并返回长度。然后,您可以从缓冲区的前面分析长度,并根据recvfrom(2)返回的内容对其进行验证。

        2
  •  2
  •   vmdm    15 年前

    另一种方法是使用msg_peek标志执行一个虚拟的recvFrom。当返回的大小与缓冲区大小(或更大)相同时,请获取更大的缓冲区,然后重试。 然后再次执行recvfrom(不带msg_peek标志)以从UDP缓冲区中删除消息。

    但是,当然,这是相当低效的,当您可以决定最大包大小时不应该这样做。