2009-10-07 63 views
9

当我通过tcp流发送()/ write()消息时,如何才能确定这些字节是否已成功发送?查明是否通过tcp发送了一条消息

接收方确认通过tcp接收字节,所以发送方tcp堆栈应该知道。但是,当我发送()一些字节时,send()立即返回,即使数据包不能传递,但我在netcat上使用strace测试了在Linux 2.6.30上,将我的网络电缆拉出之前发送一些字节。

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

回答

19

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

它通常不会将这些信息提供给发送应用程序,因为(尽管出现)它实际上并不是的意思是对于发送应用程序来说很重要。确认并不意味着接收应用程序已经获得了数据并且做了一些明智的事情 - 所有这一切意味着发送TCP不再需要担心它。数据仍然可以在传输中 - 例如,在中间代理服务器中,或在接收TCP堆栈中。

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

8

让接收器发回ack是最好的方法,即使它“感觉不舒服”。请记住,IP可能会将数据分解为多个数据包并重新组装,如果路由器中的各个路由器具有不同的MTU,则可以在传输过程中多次执行此操作,因此您对“数据包”和TCP的概念可能不同意。

更好地发送你的“数据包”,不管它是一个字符串,一个序列化的对象还是二进制数据,并让接收器做它需要做的任何检查,然后发回一个确认。

+0

事实是对的,但我不喜欢该措辞。 TCP是一种可靠的协议,如果传输失败,你将**听说它。事实上,你不需要从远程端请求ACK是一个功能,而不是一个错误。处理这个问题的“最佳”方法是在系统调用和字节级别忽略**问题。如果您需要返回结果,请在协议级别执行,而不是套接字。 – 2009-10-08 18:28:21

6

TCP协议会尽力确保您的数据到达。如果有网络问题,它会重传数据。这意味着您发送的任何内容都会被缓冲,并且没有及时的方式来确保它已经到达(如果网络关闭,2分钟后会有一个超时)。

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

+0

是的,按设计它是可靠和有序的 – RichardOD 2009-10-07 13:18:23

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 
1

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

3

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