处理来自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
:这意味着连接已关闭(这可能是您的协议的一部分发生这种情况。)