【问题标题】:Recvfrom re-reading old dataRecvfrom 重读旧数据
【发布时间】:2016-05-31 12:22:03
【问题描述】:

我正在使用 Berkeley C 套接字用 C/C++ 编写一个实时网络系统,该系统以基于滴答的间隔工作。每次滴答,客户端程序都会使用 recvfrom() 从套接字读取数据。

问题是,如果服务器没有发送任何数据,客户端会读取套接字上最后发送的数据。

例如客户端(伪代码)

while (true)
{
   if (time_to_update())
   {
      int n = recvfrom(data,...);
      printf("%s",data);
   }
}

和服务器:

int main()
{
   int m = recvfrom(data,...);
   int n = sendto(...,"hello");
}

然后客户端会一直打印“hello”,而我只需要打印一次。

这和这个问题很相似,recvfrom re-reading data on socket ,但是我不太明白这个答案,它似乎更普遍地解决了问题。

我猜数据存储在网卡上的缓冲区中,在这种情况下,在读取 1 次后是否需要清除缓冲区? 我想到的另一种方法是对数据包进行编号并仅读取新的数据包,但所有类型都是有限的,所以我希望可能有一种更清洁的方法。

我将如何做到让客户端只读取一次接收到的数据?

【问题讨论】:

  • 很可能是因为您的套接字处于非阻塞模式,您没有检查来自recvfrom() 的返回值,并且您的代码最终只是读取了您正在使用的读取缓冲区的相同内容.
  • 你为什么要根据时钟滴答声调用recvfrom(),而不是在select()(e)poll() 告诉你数据正在等待读取时进行读取?
  • 我才刚刚开始学习套接字编程,我发现的教程使用了较旧的约定,但最终我会更新我的知识。

标签: c++ c sockets recvfrom


【解决方案1】:
printf("%s",data);

常见问题。不测试错误;不测试流结束;不使用长度。应该是:

if (n < 0)
{
    perror("recv");  // or better
    break;
}
else if (n == 0)
    break; // peer has disconnected 
else
    printf("%.*s", n, data);

如果您不检查这些事情,您将永远旋转并在它们发生时打印垃圾。

我猜数据存储在网卡上的缓冲区中

没有。

在这种情况下,1 次读取后是否有清除缓冲区的方法

阅读它会清除它。您的问题出在其他地方。

【讨论】:

  • 断开连接事件不适用于 UDP 套接字。
  • @SergeyA UDP 未在问题中提及。使用recvfrom() 建议但不强制。我认为他正在使用 TCP 并且正在断开连接。他的服务器发送一次然后退出。他的客户收到一次,然后循环。如果它是UDP,它就不会做所有这些。如果有 UDP 参数错误,他根本不会收到,如果是非阻塞 UDP,他会先打印垃圾。
  • 我猜,你可能是对的。 OP应该更具体,我不应该草率​​下结论。
【解决方案2】:

您是否正在检查变量m 中的返回值?它很可能返回零或 -1(因此没有读取任何字节),并且您一遍又一遍地重新打印 data 的相同值,因为没有任何东西对其进行修改。

【讨论】:

  • UDP 套接字在 recvfrom 上不会返回 0。
  • 这有什么关系?没有人提到任何关于套接字类型的事情
  • 它当然可以从 TCP 套接字,当对方执行关闭时。
  • 这到底是怎么回事?首先,他根本没有明确提到它,所以它也可能是。其次,我并没有在我的回答中声称我特别在谈论 UDP 套接字,而不是一般的套接字。第三,他问题的语气实际上向我表明他很可能在谈论 TCP 套接字(没有提到多播或任何其他典型的 UDP 识别功能)。
  • 其实连你的开场白都是不正确的。 UDP 套接字可以recvfrom 返回 0。发送长度为零的数据报是有效的,在这种情况下它将被读取为零字节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 2020-04-01
  • 2011-08-09
  • 2010-10-15
  • 1970-01-01
相关资源
最近更新 更多