查明是不是通过 tcp 传递了消息

Posted

技术标签:

【中文标题】查明是不是通过 tcp 传递了消息【英文标题】:Finding out if a message over tcp was delivered查明是否通过 tcp 传递了消息 【发布时间】:2010-12-04 14:39:24 【问题描述】:

当我通过 tcp 流发送()/写入()消息时,我如何确定这些字节是否已成功传递?

接收方通过 tcp 确认接收到字节,因此发送方的 tcp 堆栈应该知道。

但是当我 send() 一些字节时,send() 立即返回,即使数据包(还)无法传递,我在 linux 2.6.30 上使用 netcat 上的 strace 进行了测试,在发送之前拔掉了我的网络电缆一些字节。

我只是在开发一个应用程序,其中知道消息是否已传递非常重要,但是实现 tcp 功能(“ack for message #123”)感觉很尴尬,必须有更好的方法。

【问题讨论】:

【参考方案1】:

发送 TCP 确实知道数据何时被另一端确认,但它这样做的唯一原因是它知道何时可以丢弃数据(因为其他人现在负责将数据发送给应用程序另一边)。

它通常不会向发送应用程序提供此信息,因为(尽管看起来)它实际上对发送应用程序没有多大意义。确认并不意味着接收应用程序已获得数据并对其进行了明智的处理——这只是意味着发送 TCP 不再需要担心它。数据可能仍在传输中 - 例如,在中间代理服务器中,或在接收 TCP 堆栈中。

“数据成功接收”实际上是一个应用程序级别的概念 - 它的含义因应用程序而异(例如,对于许多应用程序,只有在数据同步到磁盘后才考虑“接收”数据才有意义在接收方)。因此,这意味着您必须自己实现它,因为作为应用程序开发人员,您确实是唯一一个知道如何为您的应用程序明智地实现它的人。

【讨论】:

【参考方案2】:

让接收者发回一个确认是最好的方法,即使它“感觉很尴尬”。请记住,IP 可能会将您的数据分解为多个数据包并重新组合它们,如果途中的各种路由器具有不同的 MTU,那么这可能会在传输过程中多次完成,因此您的“数据包”概念和 TCP 可能不同意。

发送您的“数据包”要好得多,无论是字符串、序列化对象还是二进制数据,并让接收者进行所需的任何检查以使其存在,然后发回确认。

【讨论】:

事实是正确的,但我不喜欢这种措辞。 TCP 是一种可靠的协议,如果传输失败,您听到它。您不需要从远程端请求 ACK 的事实是一项功能,而不是错误。处理此问题的“最佳”方法是忽略系统调用和字节级别的问题。如果您需要返回结果,请在协议级别而不是套接字级别进行。【参考方案3】:

TCP 协议非常努力地确保您的数据到达。如果出现网络问题,它会重传几次数据。这意味着您发送的任何内容都会被缓冲,并且没有及时的方法来确保它已经到达(如果网络中断,2 分钟后会有超时)。

如果您需要快速反馈,请使用 UDP 协议。它不使用任何 TCP 开销,但您必须自己处理所有问题。

【讨论】:

是的,按照设计它是可靠且有序的【参考方案4】:

即使它到达 TCP 层,也不能保证它没有位于应用程序的缓冲区中,然后应用程序在处理它之前就崩溃了。使用确认,这就是其他所有操作(例如 SMTP)

【讨论】:

【参考方案5】:

应用层无法控制较低层(例如传输层)的通知,除非它们是专门提供的——这是设计使然。如果您想知道 TCP 在每个数据包级别上做了什么,您需要在 TCP 运行的层上找出;这意味着处理 TCP 标头和 ACK 数据。

但是,您最终用于承载有效负载的任何协议都可以用于通过该有效负载来回传递消息。因此,如果您觉得使用 TCP 标头的位来执行此操作很不方便,只需在您的应用程序中进行设置即可。例如:

A: Send 450 Bytes
B: Recv 450 Bytes
B: Send 'B received 450 Bytes'
A: Recv 'B received 450 Bytes'
A: Continue

【讨论】:

【参考方案6】:

这听起来像SCTP 可以看看;我认为它应该支持你想要的。替代方案似乎是切换到 UDP,如果您要切换协议无论如何...

【讨论】:

以上是关于查明是不是通过 tcp 传递了消息的主要内容,如果未能解决你的问题,请参考以下文章

消息传递系统-导论

消息传递系统-导论

TCP,UDP,ICMP是啥意思啊?

D-Bus 是不是保证消息传递?

gcm 云连接服务器到应用服务器消息传递

java的线程之间如何进行消息传递