例如:
客户端
...
socket.connect(server_address)
data = some_message_less_than_100_bytes
socket.sendall(data)
...
服务器端
...
socket.accept()
socket.recv(1024)
...
服务器端是否保证在一个recv()
中接收数据?
如果没有,使用标头指定消息长度的标准解决方案是如何工作的?标头本身可能已被拆分,我们必须检查标头是否已正确接收。或者页眉是固定长度的?这样,无论发送多少数据,接收器都可以以相同的方式解释前几个字节?
事实上,我正试图做一些类似的事情
客户端
while():
send()
recv()
服务器
recv()
while():
send() # Acknowledge to client
recv()
这是ravi在Linux套接字中建议的:如何让send((等待recv((
但我解决了上面描述的问题。
ravi的答案是否假设客户端和服务器都将接收到对方在单个recv((中发送的内容?
更新
我很想发布这张照片,但我不能,因为我的声誉很低。。。
以下链接是HTTP帧格式
https://datatracker.ietf.org/doc/html/rfc7540#section-4
它确实使用了一个固定长度的解决方案,因此无论头被拆分多少块,它都可以以相同的方式工作。
所以我想,某种"固定"长度是唯一的解决方案吗?即使标头大小本身是可变的,它也可能有一些承诺的位来指示标头的长度。我说得对吗?
服务器端是否保证在一个recv((中接收数据?
对于UDP,是。recv()
将返回1个完整的数据报,或者返回一个错误。不过,如果缓冲区大小小于数据报,那么数据将被截断,您无法恢复它
对于TCP,没有。唯一的保证是,如果没有发生错误,那么recv()
将返回至少1个字节,但不超过指定缓冲区大小,它可以返回介于两者之间的任何数量的字节。
如果不是,使用标头指定消息长度的标准解决方案是如何工作的?标头本身可能已被拆分,我们必须检查标头是否已正确接收。或者页眉是固定长度的?
它可以采用任何一种方式,具体取决于标头的特定格式。许多协议使用固定长度的报头,许多协议使用可变长度的报头。
无论哪种方式,您都可能需要多次调用send()
以确保发送所有相关字节,并多次调用recv()
以确保接收所有字节。TCP中的发送和读取之间没有1:1的关系。
ravi的答案是否假设客户端和服务器都将接收到对方在单个recv((中发送的内容?
Ravi的回答对send()
发送和recv()
接收的字节数没有任何假设。他的回答是从更高层次的角度提出的。但是,强制执行所需的行为是非常琐碎的,例如:
int sendAll(int sckt, void *data, int len)
{
char *pdata = (char*) data;
while (len > 0) {
int res = send(sckt, pdata, len, 0);
if (res > 0) {
pdata += res;
len -= res;
}
else if (errno != EINTR) {
if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
return -1;
}
/*
optional: use select() or (e)poll to
wait for the socket to be writable ...
*/
}
}
return 0;
}
int recvAll(int sckt, void *data, int len)
{
char *pdata = (char*) data;
while (len > 0) {
int res = recv(sckt, pdata, len, 0);
if (res > 0) {
pdata += res;
len -= res;
}
else if (res == 0) {
return 0;
}
else if (errno != EINTR) {
if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
return -1;
}
/*
optional: use select() or (e)poll to
wait for the socket to be readable ...
*/
}
}
return 1;
}
这样,您可以使用sendAll()
发送消息头,然后再发送消息数据,使用recvAll()
接收消息头,再发送消息数据。
服务器端是否保证在一个recv((中接收数据?
否。TCP是一个字节流,而不是一个消息协议。虽然在大多数情况下,它可能会处理小消息和空的发送缓冲区,但如果数据发送大于底层数据链路的MTU,它就会开始失败。TCP不保证任何原子发送recv对,但对于任何东西,除了单个八位字节。因此,即使是小数据也不要指望它。