当我通过tcp流发送()/ write()消息时,如何确定这些字节是否已成功传送?
接收方确认通过tcp接收字节,因此发送方tcp堆栈应该知道。
但是当我发送()一些字节时,send()立即返回,即使数据包还没有交付,我在linux 2.6.30上使用strace在netcat上测试,在发送之前拉出我的网线一些字节。
我正在开发一个应用程序,其中知道消息是否已传递非常重要,但实现tcp功能(“ack for message#123”)感觉很尴尬,必须有更好的方法。
答案 0 :(得分:21)
发送TCP确实知道数据何时被另一端确认,但这样做的唯一原因是它知道何时可以丢弃数据(因为其他人现在负责将数据传送到应用程序)另一边)。
它通常不会向发送应用程序提供此信息,因为(尽管有外观)它对发送应用程序实际上意味着。确认并不意味着接收应用程序已获得数据并做了一些合理的事情 - 这意味着发送TCP不再需要担心它。数据仍然可以在传输中 - 例如,在中间代理服务器内,或在接收TCP堆栈内。
“成功接收数据”实际上是一个应用程序级别的概念 - 它的含义因应用程序而异(例如,对于许多应用程序,只有在将数据同步到磁盘后才考虑“收到”数据才有意义在接收方)。所以这意味着你必须自己实现它,因为作为应用程序开发人员,你真的是唯一有能力知道如何为你的应用程序理解它的人。
答案 1 :(得分:8)
让接收者发回ack是最好的方式,即使它“感觉很尴尬”。请记住,IP可能会将您的数据分成多个数据包并重新组装它们,如果路由器中的各种路由器具有不同的MTU,这可以在传输中多次完成,因此您的“数据包”和TCP的概念可能不同意。
最好发送你的“数据包”,无论是字符串,序列化对象还是二进制数据,让接收者做任何必要的检查才能使它成为那里,然后发回一个确认。 / p>
答案 2 :(得分:6)
TCP协议非常努力地确保您的数据到达。如果存在网络问题,它将重新传输数据几次。这意味着您发送的任何内容都是缓冲的,并且没有及时的方法来确保它已到达(如果网络中断,将在2分钟后超时)。
如果您需要快速反馈,请使用UDP协议。它不使用任何TCP开销,但您必须自己处理所有问题。
答案 3 :(得分:3)
应用层无法控制较低层(例如传输层)的通知,除非它们是专门提供的 - 这是设计使然。如果您想知道TCP在每个数据包级别上正在做什么,您需要找到TCP操作的层;这意味着处理TCP标头和ACK数据。
然而,您最终用于携带有效负载的任何协议都可用于通过该有效负载来回传递消息。因此,如果您使用TCP标头的位来执行此操作感到尴尬,只需在应用程序中进行设置即可。例如:
A: Send 450 Bytes
B: Recv 450 Bytes
B: Send 'I got 450 Bytes'
A: Recv 'B got the full message'
A: Continue
答案 4 :(得分:3)
即使它已经达到TCP层,也无法保证它不会位于应用程序的缓冲区中,然后应用程序崩溃才能处理它。使用确认,这是其他所有操作(例如SMTP)
答案 5 :(得分:1)
这听起来像是SCTP可以看的东西;我认为它应该支持你想要的东西。替代方案似乎是切换到UDP,如果你正在切换协议 ......