处理来自recv()TCP的部分返回

我一直在阅读Beej的网络编程指南,以了解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); 

我将缓冲区设置为小于我发送的总字节数。 我不太确定如何获得其他字节。 我是否必须循环使用recv()直到收到'\0'

*关于服务器端的注意事项我也在实现他的sendall()函数,所以它应该实际上是将所有内容发送到客户端。

另见6.1。 指南中的简单流服务器

是的,您将需要多次recv()调用,直到您拥有所有数据。

要知道什么时候,使用recv()的返回状态是不对的 – 它只会告诉你已收到多少字节,而不是有多少字节可用,因为有些字节可能仍在传输中。

如果您收到的数据以某种方式编码总数据的长度,则会更好。 读取尽可能多的数据,直到知道长度是多少,然后读取,直到您收到length数据。 为此,可以采用各种方法; 通常的做法是,一旦知道长度是多少,就建立一个足够大的缓冲区来容纳所有数据。

另一种方法是使用固定大小的缓冲区,并且总是尝试接收min(missing, bufsize) ,在每次recv()之后减少missing

在进行TCP / IP编程时,您需要了解的第一件事:1次write / send调用可能需要多次recv调用才能接收,而多次写入/发送调用可能只需要1次recv调用即可接收。 介于两者之间。

你需要循环,直到你拥有所有数据。 recv()的返回值告诉您收到了多少数据。 如果您只想接收TCP连接上的所有数据,则可以循环直到recv()返回0 – 前提是另一端在完成发送时关闭TCP连接。

如果您要发送记录/行/数据包/命令或类似内容,则需要通过TCP创建自己的协议,这可能就像“命令用\n分隔”一样简单。

读取/解析这样一个命令的简单方法是一次读取1个字节,用接收到的字节构建缓冲区并每次检查一个\n字节。 读取1个字节的效率非常低,因此您应该一次读取更大的块。

由于TCP是面向流的,并且不提供记录/消息边界,因此它变得有点棘手 – 你必须重新获取一个字节,检查接收到的缓冲区中是否为\n字节,如果它在那里 – 将字节附加到先前收到的字节并输出该消息。 然后在\n后检查缓冲区的剩余部分,它可能包含另一条完整的消息,或者只包含另一条消息的开头。

是的,你必须遍历recv()直到你收到'\0'或发生错误(来自recv负值)或来自recv() 0 。 对于第一个选项:仅当此零是协议的一部分时(服务器发送它)。 但是,从您的代码来看,零似乎只是为了能够将缓冲区内容用作C字符串(在客户端)。

recv检查返回值为0 :这意味着连接已关闭(这可能是您的协议的一部分发生这种情况。)