2013-03-21 57 views
1

我正在使用C编写的Linux客户端服务器应用程序中使用TCP将数据复制到多个从属副本,我想知道如何处理某些副本的意外临时关闭(它可能是unix进程崩溃或硬件掉电)。从丢失的TCP连接中恢复传输

当我向内核发出write()系统调用时,成功返回意味着数据被复制到套接字,但并不意味着接收端得到了的数据。如果目标电源关闭后再通电,则数据必须从丢失数据的位置重新发送(在建立新的TCP连接后)复制副本。假设我正在处理大量数据,并且不保留已发送的数据(即write()系统调用返回成功)。我只保留待发送的数据。

当副本从意外关闭中恢复并再次连接时,如何从内核获取已写入套接字的数据,但在目标主机上不是'ack' - 尚未?或者换句话说,我如何从丢失TCP连接中恢复并重新建立客户端和服务器之间从停止点开始的传输?

回答

1

TCP会照顾需要的TCP序列号,就可以没有太大的利用者在应用层面

您需要在应用层面的一些顺序控制。

在你的情况下,你可以给你发送的每个数据块分配一个数字。目标需要持续跟踪它收到的最后一个块号。在意外关机启动时,目标需要传回它处理的最后一个块号,然后开始从那里发送。

如何从内核获取已写入套接字的数据,但在目标主机上没有“ack” - 请求?

即使你可以,这还不够。目标主机很可能会已经获得确认”的数据,但ACK可能会丢失无论出于何种原因,或从未发送,但目标应用程序可能接收和处理数据的罚款。所以如果你在这种情况下使用TCP序列号,你最终会得到重复的数据。

另一种情况是,TCP发回了数据的ack,目标应用程序在读取数据时崩溃/关闭,但恰好在它将数据写入磁盘之前。所以你最终会丢失数据。

+0

[预写日志协议](http://en.wikipedia.org/wiki/Write-ahead_logging)用于确保安全。 – 2013-03-21 15:04:50

2

您需要在TCP之上添加另一个抽象级别。在发送每一段数据之后(TCP确保它将完整无损地依次到达),让另一端的进程发送它自己的一种ACK,用你自己的更高级别的协议(不管是什么 - 不管它是什么 - ACK \ 0“,”GOT \ n“或其他)。在另一边(发起人),阅读这些数据。如果它没有错误地通过,一切都很好。如果出现错误 - 请检查类型。如果您获得ECONNRESET,那意味着远端已经死亡。从这里,你可以做出相应的回应。等到你可以重新连接,并重新发送数据。

+0

如果我必须在TCP本身上实现我自己的TCP,这让我觉得在这种情况下UDP可能更好。 – Nulik 2013-03-21 14:50:08

+1

@Nulik:不! (请不要使用UDP!请!)。 UDP并不保证任何东西*永远*在任何地方得到*,或者它以*任何顺序到达那里,或者它甚至被*发送*在第一位!这不是TCP之上的TCP,而是一个利用了TCP所有特性的小型应用程序级协议。请不要重新实施TCP。数百名专家已经完成了操作系统的实施。不要试图重做他们的工作。 – Linuxios 2013-03-21 14:52:14

2

没有办法通过标准API来做你想做的事情。

一个解决办法是让你的客户定期发送回的运行总计收到并核实写入到磁盘的字节,然后不断的发送缓冲区,但在服务器上未确认数据。然后,当客户端重新连接时,它会发送最后一个好计数,并且服务器知道从哪里开始重新发送。