查明消息是否通过 tcp 传送
当我通过 tcp 流发送()/写入()消息时,如何确定这些字节是否已成功传递?
接收方确认通过 tcp 接收字节,因此发送方 tcp 堆栈应该知道。
但是当我 send() 一些字节时,send() 立即返回,即使数据包(还)无法传递,我在 Linux 2.6.30 上使用 netcat 上的 strace 进行了测试,在发送一些字节之前拔出我的网络电缆。
我正在开发一个应用程序,了解消息是否已传递非常重要,但实现 TCP 功能(“ack for message #123”)感觉很尴尬,必须有更好的方法。
When i send()/write() a message over a tcp stream, how can i find out if those bytes were successfully delivered?
The receiver acknowledges receiving the bytes via tcp, so the senders tcp stack should know.
But when I send() some bytes, send() immediately returns, even if the packet could not (yet) be delivered, i tested that on linux 2.6.30 using strace on netcat, pulling my network cable out before sending some bytes.
I am just developing an application where it is very important to know if a message was delivered, but implementing tcp features ("ack for message #123") feels awkward, there must be a better way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
发送 TCP 确实知道数据何时被另一端确认,但它这样做的唯一原因是它知道何时可以丢弃数据(因为其他人现在负责将其发送给另一端的应用程序) )。
它通常不会向发送应用程序提供此信息,因为(尽管表面上如此)它实际上对发送应用程序没有多大意义。确认并不意味着接收应用程序已获取数据并对其进行了一些明智的操作 - 它仅意味着发送 TCP 不再需要担心它。数据可能仍在传输中 - 例如在中间代理服务器内,或在接收 TCP 堆栈内。
“数据成功接收”实际上是一个应用程序级别的概念 - 它的含义因应用程序而异(例如,对于许多应用程序来说,只有在数据在接收端同步到磁盘后才考虑数据“已接收”)边)。因此,这意味着您必须自己实现它,因为作为应用程序开发人员,您实际上是唯一一个知道如何明智地为您的应用程序执行此操作的人。
The sending TCP does know when the data gets acknowledged by the other end, but the only reason it does this is so that it knows when it can discard the data (because someone else is now responsible for getting it to the application at the other side).
It doesn't typically provide this information to the sending application, because (despite appearances) it wouldn't actually mean much to the sending application. The acknowledgement doesn't mean that the receiving application has got the data and done something sensible with it - all it means is that the sending TCP no longer has to worry about it. The data could still be in transit - within an intermediate proxy server, for example, or within the receiving TCP stack.
"Data successfully received" is really an application-level concept - what it means varies depending on the application (for example, for many applications it would only make sense to consider the data "received" once it has been synced to disk on the receiving side). So that means you have to implement it yourself, because as the application developer, you're really the only one in a position to know how to do it sensibly for your application.
让接收者发回确认是最好的方法,即使它“感觉很尴尬”。请记住,IP 可能会将您的数据分解为多个数据包并重新组装它们,如果不同的路由器具有不同的 MTU,则在传输过程中可能会多次执行此操作,因此您的“数据包”概念和 TCP 可能会不一致。
最好发送您的“数据包”,无论它是字符串、序列化对象还是二进制数据,并让接收者执行所需的任何检查以使其到达那里,然后发回确认。
Having the receiver send back an ack is the best way, even if it "feels awkward". Remember that IP might break your data into multiple packets and re-assemble them, and this could be done multiple times along a transmission if various routers in the way have different MTUs, and so your concept of "a packet" and TCP's might disagree.
Far better to send your "packet", whether it's a string, a serialized object, or binary data, and have the receiver do whatever checks it needs to do to make it it's there, and then send back an acknowledgement.
TCP 协议非常努力地确保您的数据到达。如果网络出现问题,它会重传几次数据。这意味着您发送的任何内容都会被缓冲,并且没有及时的方法来确保它已到达(如果网络中断,则会在 2 分钟后超时)。
如果需要快速反馈,请使用UDP协议。它不使用任何 TCP 开销,但您必须自己处理所有问题。
The TCP protocol tries very hard to make sure your data arrives. If there is a network problem, it will retransmit the data a few times. That means anything you send is buffered and there is no timely way to make sure it has arrived (there will be a timeout 2 minutes later if the network is down).
If you need a fast feedback, use the UDP protocol. It doesn't use any of the TCP overhead but you must handle all problems yourself.
即使它到达了 TCP 层,也不能保证它不会位于应用程序的缓冲区中,然后应用程序在处理它之前就崩溃了。使用确认,这就是其他所有操作的作用(例如 SMTP)
Even if it got as far as the TCP layer, there's no guarantee that it didn't sit in the application's buffer, then the app crashed before it could process it. Use an acknowledgement, that's what everything else does (e.g. SMTP)
应用层无法控制较低层(例如传输层)的通知,除非专门提供 - 这是设计使然。如果您想了解 TCP 在每个数据包级别上正在做什么,您需要找出 TCP 运行的层;这意味着处理 TCP 标头和 ACK 数据。
但是,您最终用于承载有效负载的任何协议都可以用于通过该有效负载来回传递消息。因此,如果您觉得使用 TCP 标头的位来执行此操作感到尴尬,只需在应用程序中进行设置即可。例如:
Application layer has no control over the notifications at lower layers (such as the Transport layer) unless they are specifically provided - this is by design. If you want to know what TCP is doing on a per packet level you need to find out at the layer that TCP operates at; this means handling TCP headers and ACK data.
Any protocol you end up using to carry your payload can be used to pass messages back and forth by way of that payload, however. So if you feel awkward using the bits of a TCP header to do this, simply set it up in your application. For instance:
这听起来像是 SCTP 值得关注;我认为它应该支持你想要的。另一种选择似乎是切换到 UDP,如果您要切换协议无论如何...
This sounds like SCTP could be something to look at; I think it should support what you want. The alternative seems to be to switch to UDP, and if you're switching protocols anyway…