【问题标题】:Getting number of bytes available to read in a socket获取套接字中可读取的字节数
【发布时间】:2012-02-02 07:26:49
【问题描述】:

这是我的场景。我有一个与服务器通信的 TCP 客户端。服务器和客户端都在本地机器(Windows)上运行。

对话框如下:

  1. 客户端向服务器发送数据(请求)
  2. 客户端确实关闭了套接字上的发送
  3. 客户端通过读取响应阻塞
  4. 服务器接收数据、处理并发回响应(一次性,未分成块)
  5. 服务器关闭以在套接字上发送
  6. 客户端收到响应,并继续处理。

在第 3 步,我正在使用 recv() 调用来阻止并从套接字读取数据。此时,我想偷看一下有多少字节的数据可用,这样我就可以分配这么多的内存。 通过设计,知道服务器已经发送了所有数据,并且没有更多数据可以发送这个请求。 (参见上面的第 5 步)。

我已经尝试使用带有 MSG_PEEK 选项的 recv(),但这似乎没有给出可用的字节总数。

有办法找回吗?

提前致谢。

【问题讨论】:

  • 仅仅因为服务器已经发送了所有数据,这并不意味着它们会同时到达。仅仅因为 recv() 返回并不意味着你已经得到了一切。您应该继续调用 recv() 直到 in 通过返回 0 表明没有任何剩余
  • 我在这里说的是无知,但我怀疑答案是否定的,因为内核在收到所有数据包之前无法知道总字节数。这可能要等到客户提出要求后才会发生。所以你能希望的最好的就是一个下限,这就是 MSG_PEEK 给你的。

标签: c++ sockets recv peek


【解决方案1】:

至少在 Windows 上,您可以使用 ioctlsocket()FIONREAD 命令来确定当前可供 recv() 无阻塞读取的字节数。但是,当您实际调用 recv() 时,可能已经到达了更多字节。

正如@LokiAstari 所说,您应该在循环中调用recv(),直到它返回0 字节以指示套接字已关闭。您不需要知道有多少字节可用,只需每次传递一个固定长度的缓冲区,recv() 将返回实际读取了多少字节。将读取的每个非零长度缓冲区附加到另一个缓冲区,该缓冲区会根据需要增长,直到您收到所有数据,然后在准备好时处理第二个缓冲区。

【讨论】:

    【解决方案2】:

    在不预先分配或重新分配缓冲区的情况下执行此操作的一种方法是:(a) 发送发送方正在发送的字节数(例如,作为四字节 int,按网络字节顺序),(b ) 让接收者接收这四个字节并分配一个接收缓冲区,然后 (c) 让接收者发送先前发送长度的实际数据。请注意,(c) 可能由发送方发生,而不会收到来自接收方的关于 (a) 的反馈或回复。

    我一直在尝试使用 fstat 来获取套接字上可用的数据量,但它似乎不可移植。在 Mac 系统上,它适用于我的应用程序。在 Linux 系统上,它不会。

    【讨论】:

      【解决方案3】:

      使用 TCP 无法知道有多少字节。请记住,TCP 是一种“流”协议,流有一个开始,但在连接关闭之前没有结束。

      您可以做的是将小块读入缓冲区,并在需要时扩大缓冲区。

      【讨论】:

      • 如果缓冲区的大小超过了可用的字节数怎么办,因此,我们正在尝试读取比套接字提供的更多的字节数。
      • @sumitdhyani 然后您将获得可用的数据,除非您将recvMSG_WAITALL 一起使用,在这种情况下,调用将阻塞,直到系统收到足够的数据来满足您的请求。跨度>
      • 但是如果连接已经关闭,recv 返回了0,我只需要知道接收到的字节在我的缓冲区中的哪里结束?在哪里放置\0 字符来终止接收到的字符串,因为我的缓冲区可能包含随机字节。
      • @xealits 如果recv 返回0,那么它没有向缓冲区写入任何内容,自上次成功调用recv 以来,缓冲区的内容未修改。所以对你来说,解决方案是在每次调用 recv 后设置字符串空终止符,它会返回一个正值。
      【解决方案4】:

      这部分取决于响应的大小,因为即使将其作为一个块发送,底层传输也可能将其分成多个块。例如,以太网的最大数据包大小为 1500 字节。尽管您一次发送所有信息,但您可能会一次收到所有信息,但不能保证您是否使用 TCP,因为它是面向流的。如果您使用 UDP,则更有可能以单个数据包的形式接收响应。

      【讨论】:

        猜你喜欢
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-20
        • 1970-01-01
        • 2017-05-18
        • 2021-04-25
        • 1970-01-01
        相关资源
        最近更新 更多