在 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 是不是会关闭套接字?

握手4

在c ++中使用multipe recv()和send()调用

来自客户端的Getchar()在套接字编程中

TCP:recv() 获取 ECONNRESET

通过解析 json 在 gen_tcp:recv 上接收的字节