如何判断套接字recv()函数在返回值0时收到了多少数据?

时间:2016-09-24 06:45:02

标签: c sockets network-programming

这似乎是一个愚蠢的问题,但它一直让我疯狂。我正在进行网络编程分配,我编写的代码的一部分是使用缓冲区,缓冲区长度和为标志指定的零调用套接字recv()函数。 recv()调用返回零值,并且手册页显示返回值为零表示'流套接字对等已执行有序关闭。'

问题是recv()调用确实接收了数据,并且确实更新了我的缓冲区。我知道因为我可以使用printf将其打印出来,并且我希望在recv()调用期间收到的数据显示在printf输出中。但问题是,由于recv()返回零,我真的不知道实际上有多少数据放入我的缓冲区。我在缓冲区上做了一个memset,在我使用它之前将其归零,所以我想我之后可以对缓冲区执行strlen()调用,但这看起来像是一个hack。这是我想要做的吗?

另一件事是套接字仍处于打开状态,因为我在第一次recv()调用后不久就在while循环中循环遍历套接字并继续接收更多数据。我正在使用的缓冲区的大小是char缓冲区[4096]数组。任何见解将不胜感激。

4 个答案:

答案 0 :(得分:3)

  

问题是recv()调用确实接收了数据,并且确实更新了我的缓冲区。我知道因为我可以使用printf将其打印出来,并且我希望在recv()调用期间收到的数据显示在printf输出中。问题是,因为recv()返回零,我真的不知道实际上有多少数据放入我的缓冲区。

这根本不可能。 recv()可以:

  1. 接收1个或多个字节,并返回一个正值,指定接收的字节数。
  2. 正常关机时返回0,没有收到数据。
  3. 如果请求0字节则返回0。
  4. 错误时返回-1。
  5. 就是这样。 recv()无法接收某些数据但返回0.它无法正常工作。它是一个或另一个。

      

    另一件事是套接字仍处于打开状态,因为我在第一次recv()调用后不久在while循环中循环遍历套接字并继续接收更多数据。

    可能发生的唯一方式是,如果第一个recv()返回0,因为请求了0个字节,而不是因为发生了关闭。如果发生了实际关闭,所有后续读取将不再接收任何数据。他们不能。通过接收FIN数据包来发出正常关闭信号,这意味着将不再发送数据。发送FIN后,发件人的套接字堆栈将不允许再发送任何数据。这是TCP工作方式的一部分。

    你的代码中显然有一个错误(你没有显示)。有时,您必须将缓冲区大小0传递给recv(),使其返回0.这是后续读取在给定非零缓冲区大小时仍然可以接收更多数据的唯一方法。

答案 1 :(得分:2)

哦,天哪。我发现问题是什么,这是一个非常基本的错误。确保在if语句中检查括号的顺序。以下是出错的代码。

enter image description here

如果你看,你可以在最右边看到两个右括号。在小于号码之前应该有两个右括号,在最右边有一个右括号。

我发现这是因为我在拍摄截图后编辑了我的回复,并在我提交之前不久查看我编辑过的问题时注意到了这一点。这就是当您在前一天晚上2:30睡觉前6小时处理代码时会发生的情况。

再次感谢大家,并保重。

答案 2 :(得分:1)

由于您没有提供任何代码,我无法确切说明您的问题在哪里。但如果你这样做,它应该按预期工作:

    ssize_t bytes_read = 0;

    while ((bytes_read = recv(sock_fd, buffer, sizeof buffer, 0)) > 0) {
        printf("Bytes received: \t%zd\n", bytes_read);
        // ...
    }

您可以在此处看到recv()在返回0或负值后不再被调用。

此外,我不会使用memset()在每次迭代时将缓冲区归零,这是低效的,只是浪费了周期。而是读取bufferrecv()bytes_read中返回的字节数。

我可以看到,Remy Lebeau也已经指出了其他一些细节。

答案 3 :(得分:1)

  

手册页显示返回值为零表示'流套接字对等已执行有序关闭。'

不仅如此,它还意味着您在获得此零之前已收到对等方发送的所有数据。

  

问题是recv()调用实际上确实收到了数据,并确实更新了我的缓冲区。

不,它没有。

  

我知道因为我可以使用printf将其打印出来,并且我希望在recv()调用期间收到的数据显示在printf输出中。

它已经存在了。

  

问题是,由于recv()返回零,我真的不知道实际上有多少数据放入我的缓冲区。

没有数据放入缓冲区。它没有受到任何干扰。传输的字节数为零。这是它的意思。

  

我在缓冲区上做了一个memset,在我使用之前将其归零0

不要这样做。它的货物崇拜节目。这在任何方面都是不必要的。它只是更多的代码,更多的时间,更多的空间,都浪费了。

  

,所以我想我之后可以在缓冲区上执行strlen()调用,但这看起来像是一个黑客。这是我想要做的吗?

没有。 TCP已经提供了返回值,并且它也不排除具有内部空字节的数据。这里有更多的货物崇拜节目。

  

另一件事是套接字仍处于打开状态

正确。它一直打开,直到你关闭它。

  

因为我在第一次recv()调用后不久在while循环中循环遍历套接字并继续接收更多数据。

不可能,抱歉。

我喜欢@ RemyLebeau的建议,你已经通过零长度作为解释。