这是我的情景 . 我有一个与服务器通信的TCP客户端 . 服务器和客户端都在本地计算机(Windows)上运行 .
对话框如下:
-
客户端将数据发送到服务器(请求)
-
客户端关闭套接字上的send
-
客户端通过读取调用进行响应
-
服务器接收数据,处理并发回响应(一次性,不分成块)
-
服务器关闭套接字上的发送
-
客户端收到响应,并继续处理 .
在步骤3,我使用recv()调用来阻塞和读取套接字中的数据 . 在这一点上,我想看看有多少字节的数据可用,这样我就可以分配这么多的内存 . 根据设计,已知服务器已发送所有数据,并且没有更多数据可用于发送此请求 . (见上文第5步) .
我已经尝试使用MSG_PEEK选项的recv(),但似乎没有给出可用的总字节数 .
有没有办法检索它?
提前致谢 .
4 回答
在没有预先分配或重新分配缓冲区的情况下,这样做的一种方法是:(a)发送发送方正在发送的字节数(例如,以网络字节顺序的四字节int),(b)具有接收器接收这四个字节并分配接收缓冲器,然后(c)让接收器发送先前发送长度的实际数据 . 注意,(c)发送者可以在没有收到关于(a)来自接收者的反馈或回复的情况下发生 .
我一直在尝试使用fstat来获取套接字上可用的数据量,但它似乎不是可移植的 . 在Mac系统上,它适用于我的应用程序 . 在Linux系统上,它没有 .
使用TCP无法知道有多少字节 . 请记住,TCP是一种“流”协议,在连接关闭之前,流有一个开始但没有结束 .
你可以做的是将小块读入缓冲区,并在需要时放大缓冲区 .
至少在Windows上,您可以使用带有
FIONREAD
命令的ioctlsocket()
来确定recv()
可以无阻塞地读取的当前字节数 . 当你实际调用recv()
时,可能会有更多字节到达 .正如@LokiAstari所说,你应该在一个循环中调用
recv()
,直到它返回0个字节来指示套接字已经关闭 . 您不需要知道可用的字节数,每次只传递一个固定长度的缓冲区,recv()
将返回实际读取的字节数 . 将每个非零长度缓冲区读取附加到另一个缓冲区,该缓冲区根据需要增长,直到您收到所有数据,然后在准备好后处理第二个缓冲区 .它部分取决于响应的大小,因为即使将其作为一个块发送,底层传输也可能将其分解为块 . 例如,以太网的最大包大小为1500字节 . 虽然您只发送一次,但很可能您将同时收到所有内容,但如果您使用的是TCP,则无法保证,因为它是面向流的 . 如果使用UDP,则更有可能以单个数据包的形式接收响应 .