我在Windows上使用阻塞C套接字。
我使用它们将数据的更新从服务器发送到客户端,反之亦然。我以高频率(每100毫秒)发送更新。 send()
函数是否会等待收件人recv()
在结束前收到数据?
如果我理解了这个手册页,我不会假设:
“send()的成功完成并不能保证传递信息。”
那么如果一个人发生了10 send()
次发生而另一个只完成了1 recv()
会发生什么?
我是否需要使用某种确认系统?
答案 0 :(得分:11)
让我们假设您正在使用TCP。当您调用send时,您发送的数据会立即放在传出队列上,然后发送成功完成。但是,如果send无法将数据放在传出队列上,send将返回错误。
由于Tcp是保证传送协议,因此只有在远程端收到确认后,才能删除传出队列上的数据。这是因为如果没有及时收到确认,可能需要重新发送数据。
如果远程端缓慢,传出队列将填满数据,然后发送将阻塞,直到有空间将新数据放在传出队列上。
然而,连接失败的方式是无法再发送任何其他数据。虽然TCP连接一旦关闭,任何进一步的发送都将导致错误,用户无法知道实际上有多少数据到达另一方。 (我知道无法从套接字检索TCP簿记到用户应用程序)。因此,如果需要确认接收数据,则应该在应用程序级别实现此功能。
对于UDP,我认为不言而喻,某种方式报告已收到或未收到的内容是必须的。
答案 1 :(得分:8)
send()
阻塞,直到操作系统(内核)获取数据并将其放入传出数据的缓冲区中。它不会等到另一端收到数据。
答案 2 :(得分:2)
如果您通过TCP发送,您将获得保证交付 1 ,另一端将按发送的顺序接收数据。但是,这可能会合并在一起,因此您发送的10个单独更新可以作为单个大数据包接收(反之亦然 - 单个更新可以在任意数量的数据包中分解)。这意味着,除其他外,任何数据的任何ACK都会隐式确认收到所有先前的数据。
如果您正在使用UDP,那么这些都不是真的 - 数据可能无序到达,或者被丢弃而根本无法传送。如果您关心所有收到的数据,您只需要在UDP本身之上构建自己的某种确认系统。
1 当然,保证是有限制的 - 如果网络电缆被切断(或其他)数据包将无法传送,但您至少会收到错误消息你连接丢失了。
答案 3 :(得分:0)
如果你正在使用TCP,你可以免费获得确认,因为这是协议所做的一部分。但听起来像这种类型的应用程序,你可能想要使用UDP。在任何一种情况下,send()
都不会阻止,直到客户端成功recv()
。
如果客户端收到每条消息至关重要,那么请使用TCP。如果客户端可以错过一条或多条消息,则使用UDP。
答案 4 :(得分:0)
TCP保证在较低的TCP堆栈级别交付。它重试传递,直到接收部分确认已收到数据,但您的应用程序可能永远不知道该事实。
让我们假设您正在发送数据块,并且您需要根据某些逻辑将这些数据块放在某处。如果您的应用程序不准备知道每个块必须放在哪里,那么在TCP级别接收它可能是无用的。原帖是关于应用程序级逻辑的。