使用Winsock的send()/ recv()时是否需要确认响应?

时间:2011-06-11 22:39:00

标签: c++ tcp winsock send recv

使用Winsock,C ++,我通过 send()/ recv(),TCP连接发送和接收数据。我想确保数据已经传递给另一方,并且想知道是否建议在(如果)使用 recv 接收数据后发回一些确认消息。

以下是两种可能性,请提出建议:

  1. 如果发送返回已传递缓冲区的大小,则假设数据已至少传送到线路另一侧的 recv 功能。当我说“至少”时,我的意思是即使 recv 在那里失败(例如由于缓冲不足等),我也不在乎,我只是想确定我已经完成了我的服务器部分工作正常 - 我已完全发送数据(即数据到达另一台机器)。

  2. 使用附加确认:在收到带有 recv 的数据后,发回一些收到的数据包ID(发送的每个数据的标题的一部分),表示该数据包的成功接收操作。如果我在一段时间后没有收到这样的“确认消息”,则从发送者功能返回失败代码。

  3. 第二个答案看起来更安全,但如果冗余,我不想让传输协议复杂化。另请注意,我在谈论TCP连接(它本身比UDP更安全)。

    是否有其他机制(可能是某些其他API?可能 WSARecv()/ WSASend()以不同的方式工作?)确保数据已传递到 recv 功能在另一边?

    如果你推荐第二种方式,请给我一些代码片段,允许我使用带有超时的 recv 来接收确认? recv 是阻止操作,因此如果先前的发送尝试失败(另一方未收到通知),它将永久挂起。有没有使用 recv 超时的简单方法(每次都不创建单独的线程,这可能是每次发送操作的过度杀伤)。

    我传递给发送功能的数据量也可能很大(几兆字节),那么如何选择“确认消息”的超时?也许我应该“拆分”大缓冲区并使用几个发送调用?我认为它会变得相当复杂,请指教!

    编辑:好的,你们有人建议TCP / IP堆栈处理它(即不需要手动确认),但这是我在MSDN页面上找到的:“发送成功完成功能并不表示数据已成功传递并接收到收件人。此功能仅表示数据已成功发送。“因此,即使TCP机制能够确保数据传递,我也无法通过 send()函数或我知道的任何其他Winsock函数获得该状态(成功与否)。你知道从TCP层获取状态的任何方法吗?再次 - send()函数的返回值似乎还不够!

    =============================================== =========

    编辑2:好的,我认为我们同意即使TCP协议在出现问题时考虑错误处理,Winsock的 send()功能也无法报告错误(仅仅因为它在网络驱动程序开始实际传输数据之前返回)。所以这里有一个百万美元的问题:Winsock的 send()函数是否至少确保在当前数据包出现之前不会将其他数据包传递给另一方?换句话说,如果发送失败导致某些网络故障(但未通过发送()呼叫报告),则在下次调用 send()之前将修复网络故障具有下一个数据块的功能,是否可以确保先前的数据包(失败但未通过 send()报告)将在下一个数据包之前传送?换句话说,一个特定的send()函数是否有可能“静默”失败,以便后续的send()调用成功,但第一个数据包将丢失?再次 - 我不是在谈论TCP级别,我正在谈论Winsock API级别!

4 个答案:

答案 0 :(得分:3)

为什么不相信您的TCP / IP堆栈以保证交付。毕竟,这是使用TCP而不是UDP的全部要点。

答案 1 :(得分:3)

此处的现有答案大多是正确的:如果您使用TCP,您实际上无需担心将数据包可靠地传送给您的同行。

但对于某些系统而言,这是一个危险的观点,其中必须将数据完整性提升到下一个级别:审核要求FAU_STG.4.1的通用标准要求阻止可审核事件的能力如果审核日志可能会丢失审核条目。 (例如,可以将Linux auditd(8)审核日志记录守护程序配置为将计算机置于单用户模式,或者在没有剩余空间用于审核日志时完全停止系统。)来自远程系统的审核日志应该可能会被维护,直到已知它们已成功写入集中式日志服务器。

使用比简单TCP更可靠的协议可能最好地处理金融交易 - 使用多阶段协议最好处理贷记或借记账户以确保资金的可用性,执行交易,然后报告结果交易到起点。

TCP在两个对等体之间允许nearly a gigabyte of in-flight data(在极端条件下);根据应用程序的要求,您可能需要在发送端维护该数据,直到您从对等方收到正确处理数据的肯定确认。

值得庆幸的是,大多数应用程序并不重要;在这里或那里丢失一兆字节的数据,在“未来”的某个时刻报告关闭连接的套接字确实并不可怕 - 我们只是重新尝试我们的HTTP请求,或者重新尝试SFTP连接。

<强>更新

套接字只接受足够的数据来填充其可用的窗口。在会话握手期间,窗口大小在两个对等端之间协商。所以当套接字窗口填满时,对send()的调用将开始阻塞。 (操作系统可能继续允许您将数据添加到其内部缓冲区,但在某些时候写入将阻止。)如果对等方断开与RST或{{1}的连接}无法访问的消息,对ICMP future 调用将返回Connection Reset或Broken Pipe的错误值。

更新2

  

我不是在谈论TCP级别,我正在谈论Winsock API级别

这可能是混乱的根源。 send()别无选择,只能在与TCP一起使用时遵守TCP行为。

TCP保证按顺序可靠地传送字节流,达到可以传送数据包的程度。 (参见@Hans关于小马和粗心的人踢电源线的评论。)对等程序以正确的顺序查看字节。 (好吧,好吧,TCP out-of-band紧急数据包传递,但我实际上没有看到任何使用它的应用程序。使用OOB数据包,你可以获得一些数据 - 忘了我提到了。)

如果远程程序接收到TCP流上发送的字节,它也可靠地接收所有前面的字节。 (好吧,有replay attacks的整个类将远程对等的合法伪包拼接在一起,但是在具有随机初始序列号的系统上这些变得越来越困难。如果这是在你的威胁模型中,你应该使用TLS在TCP之上提供加密强大的防篡改信息。但是TLS无法提供更好的每包传送通知。)

答案 2 :(得分:1)

如果你使用UDP并且你关心另一方实际收到的数据你需要使用ACK,但是如果你不需要UDP的速度,你应该使用TCP,因为它会为你确认。

答案 3 :(得分:0)

我认为您已经过度复杂,相信您的TCP / IP软件堆栈及其提供的可靠交付。 TCP套接字操作数据流,而不是数据包。另外,拨打send的电话不能保证只能拨打recv