在 C 中处理来自 recv() TCP 的部分返回
Posted
技术标签:
【中文标题】在 C 中处理来自 recv() TCP 的部分返回【英文标题】:Handling partial return from recv() TCP in C 【发布时间】:2009-09-06 17:06:55 【问题描述】:我一直在阅读 Beej's Guide to Network Programming 以了解 TCP 连接。在其中一个示例中,简单 TCP 流客户端的客户端代码如下所示:
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1)
perror("recv");
exit(1);
buf[numbytes] = '\0';
printf("Client: received '%s'\n", buf);
close(sockfd);
我已将缓冲区设置为小于我发送的总字节数。我不太确定如何获得其他字节。在收到'\0'
之前,我是否必须遍历recv()
?
*注意在服务器端我也在实现他的sendall()
函数,所以它实际上应该将所有内容发送到客户端。
另请参阅指南中的 6.1. A Simple Stream Server。
【问题讨论】:
【参考方案1】:是的,您将需要多次recv()
调用,直到获得所有数据。
要知道那是什么时候,使用来自recv()
的返回状态是不好的 - 它只会告诉您您收到了多少字节,而不是有多少字节可用,因为有些可能仍在传输中。
如果您收到的数据以某种方式对总数据的长度进行编码,那就更好了。读取尽可能多的数据直到知道长度是多少,然后读取直到收到length
数据。为此,可以采用多种方法;常见的方法是在知道长度后使缓冲区足够大以容纳所有数据。
另一种方法是使用固定大小的缓冲区,并始终尝试接收min(missing, bufsize)
,在每个recv()
之后减少missing
。
【讨论】:
如果您确定该值不能出现在消息中,或者起始字节 (STX) 和结束字节 (ETX) 中,则另一种方法是使用具有特殊值的结束字节(如 ETX)。在接收端更难处理,但更健壮。如果出现问题并且在传输过程中丢失了一些数据,数据流可以很容易地与 STX/ETX 同步,但在长度前缀的情况下,所有的地狱都会崩溃【参考方案2】:在进行 TCP/IP 编程时需要学习的第一件事:1 write
/send
调用可能需要
几个recv
调用来接收,几个写/发送调用可能只需要1 个recv
调用来接收。以及介于两者之间的任何东西。
您需要循环,直到获得所有数据。 recv()
的返回值告诉您收到了多少数据。如果您只是想接收 TCP 连接上的所有数据,则可以循环直到 recv()
返回 0
- 前提是另一端在发送完成后关闭 TCP 连接。
如果您要发送记录/行/数据包/命令或类似的东西,则需要通过 TCP 制定自己的协议,这可能就像“命令以 \n
分隔”一样简单。
读取/解析此类命令的简单方法是一次读取 1 个字节,用接收到的字节构建缓冲区,并每次检查 \n
字节。读取 1 个字节的效率极低,因此您应该一次读取更大的块。
由于 TCP 是面向流的并且不提供记录/消息边界,它变得有点棘手 - 你会
必须recv
一个字节,检查接收的缓冲区是否有\n
字节,如果它在那里 - 将字节附加到先前接收的字节并输出该消息。然后检查\n
之后的缓冲区的剩余部分 - 这可能包含另一条完整消息或只是另一条消息的开头。
【讨论】:
【参考方案3】:是的,您必须遍历 recv()
直到收到 '\0'
或
发生错误(来自recv
的负值)或来自recv()
的0
。
对于第一个选项:仅当此零是您的一部分时
协议(服务器发送它)。但是从您的代码看来
零只是为了能够将缓冲区内容用作
C 字符串(在客户端)。
检查recv
的返回值0
:
这意味着连接已关闭(它可能是一部分
发生这种情况的协议。)
【讨论】:
你可以接收值为'\0'的字节;问题是当返回的字节数为 0 时。 他为什么会收到\0
?除非他送了一个?问题中没有关于这一点的证据。以上是关于在 C 中处理来自 recv() TCP 的部分返回的主要内容,如果未能解决你的问题,请参考以下文章
如果达到超时,gen_tcp:recv/3 是不是会关闭套接字?