在 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
Handling partial return from recv() TCP in C
提问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.
回答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 length
data. 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 missing
after each recv()
.
另一种方法是使用固定大小的缓冲区,并始终尝试接收min(missing, bufsize)
,missing
在每个 之后减少recv()
。
回答by nos
The first thing you need to learn when doing TCP/IP programming: 1 write
/send
call might take
several recv
calls to receive, and several write/send calls might need just 1 recv
call to receive. And anything in-between.
在进行 TCP/IP 编程时,您需要了解的第一件事是:1 write
/ send
call 可能需要多次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 \n
byte 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 recv
a piece of bytes, check in the received buffer for a \n
byte, 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 0
from 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 0
from recv
:
this means that the connection was closed (it could be part
of your protocol that this happens.)
检查0
from的返回值recv
:这意味着连接已关闭(发生这种情况可能是您的协议的一部分。)