在 C 中处理从 recv() TCP 的部分返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1386142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:48:16  来源:igfitidea点击:

Handling partial return from recv() TCP in C

c++csocketstcp

提问by whatWhat

I've been reading through Beej's Guide to Network Programmingto get a handle on TCP connections. In one of the samples the client code for a simple TCP stream client looks like:

我一直在阅读Beej 的网络编程指南以了解 TCP 连接。在其中一个示例中,简单 TCP 流客户端的客户端代码如下所示:

if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    exit(1);
}

buf[numbytes] = '##代码##';

printf("Client: received '%s'\n", buf);

close(sockfd);

I've set the buffer to be smaller than the total number of bytes that I'm sending. I'm not quite sure how I can get the other bytes. Do I have to loop over recv()until I receive '\0'?

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

*Note on the server side I'm also implementing his sendall()function, so it should actually be sending everything to the client.

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

See also 6.1. A Simple Stream Serverin the guide.

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

回答by Martin v. L?wis

Yes, you will need multiple recv()calls, until you have all data.

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

To know when that is, using the return status from recv()is no good - it only tells you how many bytes you have received, not how many bytes are available, as some may still be in transit.

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

It is better if the data you receive somehow encodes the length of the total data. Read as many data until you know what the length is, then read until you have received lengthdata. To do that, various approaches are possible; the common one is to make a buffer large enough to hold all data once you know what the length is.

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

Another approach is to use fixed-size buffers, and always try to receive min(missing, bufsize), decreasing missingafter each recv().

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

回答by nos

The first thing you need to learn when doing TCP/IP programming: 1 write/sendcall might take several recvcalls to receive, and several write/send calls might need just 1 recvcall to receive. And anything in-between.

在进行 TCP/IP 编程时,您需要了解的第一件事是:1 write/ sendcall 可能需要多次recv调用才能接收,而多次 write/send 调用可能只需要一次recv调用即可接收。以及介于两者之间的任何东西。

You'll need to loop until you have all data. The return value of recv()tells you how much data you received. If you simply want to receive all data on the TCP connection, you can loop until recv()returns 0- provided that the other end closes the TCP connection when it is done sending.

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

If you're sending records/lines/packets/commands or something similar, you need to make your own protocol over TCP, which might be as simple as "commands are delimited with \n".

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

The simple way to read/parse such a command would be to read 1 byte at a time, building up a buffer with the received bytes and check for a \nbyte every time. Reading 1 byte is extremely inefficient, so you should read larger chunks at a time.

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

Since TCP is stream oriented and does not provide record/message boundaries it becomes a bit more tricky - you'd have to recva piece of bytes, check in the received buffer for a \nbyte, if it's there - append the bytes to previously received bytes and output that message. Then check the remainder of the buffer after the \n- which might contain another whole message or just the start of another message.

由于 TCP 是面向流的并且不提供记录/消息边界,因此它变得更加棘手 - 您必须使用recv一个字节,检查接收到的缓冲区中的一个\n字节,如果它在那里 - 将字节附加到以前接收的字节并输出该消息。然后检查\n-之后缓冲区的剩余部分,它可能包含另一条完整的消息或只是另一条消息的开头。

回答by Peter Mortensen

Yes, you have to loop over recv()until you receive '\0'or an error happen (negative value from recv) or 0from recv(). For the first option: only if this zero is part of your protocol (the server sends it). However from your code it seems that the zero is just to be able to use the buffer content as a C-string (on the client side).

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

The check for a return value of 0from recv: this means that the connection was closed (it could be part of your protocol that this happens.)

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