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

wha*_*hat 13 c c++ sockets 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);
Run Code Online (Sandbox Code Playgroud)

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

*在服务器端注意我也在实现他的sendall()功能,所以它应该实际上是将所有内容发送到客户端.

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

Mar*_*wis 15

是的,recv()在您拥有所有数据之前,您需要多次通话.

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

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

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

  • 另一种方法是使用具有特殊值的结束字节(如ETX),如果您确定该值不能出现在消息中,或者启动字节(STX)和结束字节(ETX).在接收器端处理起来更困难,但更强大.如果出现问题并且传输中丢失了一些数据,数据流可以很容易地与STX/ETX同步,但是如果长度为前缀,所有地狱都会松动 (6认同)

nos*_*nos 11

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

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

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

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

由于TCP是面向流的,并且不提供记录/消息边界,所以它变得有点棘手 - 你需要recv一个字节,检查接收缓冲区中的\n字节,如果它在那里 - 将字节附加到先前接收的字节并输出该消息.然后在\n- 之后检查缓冲区的剩余部分- 可能包含另一条完整的消息或仅包含另一条消息的开头.