【发布时间】:2011-09-13 05:16:37
【问题描述】:
使用 Winsock、C++,我通过 send()/recv()、TCP 连接发送和接收数据。我想确定数据是否已经传递给对方,想知道是否建议(如果)用recv接收数据后发回一些确认消息。
这里有两种可能,请指教:
如果 send 返回传递缓冲区的大小,则假定数据至少已传送到线路另一端的 recv 函数。当我说“至少”时,我的意思是即使 recv 在那里失败(例如由于缓冲区不足等),我不在乎,我只是想确定我已经完成了我的服务器部分工作正常 - 我已完全发送数据(即数据到达另一台机器)。
使用附加确认:在接收到带有 recv 的数据后,发回接收到的数据包的一些 ID(发送的每个数据的标头的一部分),表明该数据包的成功接收操作。如果在一段时间后我没有收到这样的“确认消息”,则从发送函数返回失败代码。
第二个答案看起来更安全,但如果它是多余的,我不想让传输协议复杂化。另请注意,我说的是 TCP 连接(它本身比 UDP 更安全)。
是否有任何其他机制(可能是其他一些 API?也许 WSARecv()/WSASend() 工作方式不同?)确保将数据传递到 recv另一边的功能?
如果你推荐第二种方式,你能否给我一些代码 sn-p 允许我使用 recv 超时来接收确认? recv 是一个阻塞操作,因此如果之前的发送尝试失败(未通知对方),它将永远挂起。是否有任何简单的方法可以在超时的情况下使用 recv (无需每次都创建单独的线程,这可能是每个 send 操作的过度杀伤力)。
另外,我传递给 send 函数的数据量可能很大(几兆字节),那么如何选择“确认消息”的超时时间呢?也许我应该“拆分”大缓冲区并使用多个 send 调用?我觉得会很复杂,请指教!
编辑:好的,你们建议 TCP/IP 堆栈将处理它(即不需要手动确认),但这是我在 MSDN 页面上找到的:“send 的成功完成函数并不表示数据已成功发送和接收到接收方。此函数仅表示数据已成功发送。"因此,即使 TCP 机制有能力确保数据传递,我也无法通过 send() 函数或我知道的任何其他 Winsock 函数获得该状态(成功与否)。您知道从 TCP 层获取状态的任何方法吗?再次 - send() 函数的返回值似乎还不够!
================================================ =========
编辑 2:好的,我认为我们同意即使 TCP 协议在出现问题时考虑错误处理,但 Winsock 的 send() 函数无法报告错误(仅仅是因为它在网络驱动程序开始实际传输数据之前返回)。所以这里有一个百万美元的问题:Winsock 的 send() 函数是否至少确保在当前数据包发送之前不会有其他数据包发送给对方?换句话说,如果由于某些网络故障而发送失败(但 send() 调用未报告),则网络故障将在下一次 send() 调用之前修复 strong> 功能与下一个数据块,是否确保前一个数据包(失败但 send() 未报告)将在下一个数据包之前传递?换句话说,一个特定的 send() 函数是否有可能“静默”失败,以便后续的 send() 调用会成功但第一个数据包会丢失?再次 - 我不是在谈论 TCP 级别,我是在谈论 Winsock API 级别!
【问题讨论】:
-
你要一匹小马。 TCP 保证交付。它会,它需要 send() 缓冲区并立即返回,承诺交付它。但是对于 8.5 级地震之后的海啸没有很好的解决方法。或有人绊倒电源线。这有关系吗?当这种情况发生时,没有更大的事情需要担心吗?如果你说“不!”那就不要使用 TCP。
-
记住数据包仅以光速传播可能是明智之举。 50 毫秒的行程时间并不罕见。如果操作系统希望每秒发送超过 20 个数据包 (~30 kB/s),则操作系统必须在第一个数据包到达之前发送第二个数据包。显然,在发送第二个数据包之前,操作系统不能等待 100 毫秒来确认第一个数据包到达。您的 LAN 可能更快,例如 100 us,但在每个数据包后等待 200 us 会将您的 LAN 限制为 5000 个数据包/秒 = 7.5 MB/秒。也不是很好。