我正在研究用C编写的用于Linux的客户端服务器应用程序,我正在使用TCP将数据复制到多个从属副本,我想知道如何处理某些副本的意外临时关闭(可能是崩溃的unix进程或硬件断电)。
当我向内核发出write()系统调用时,成功返回意味着数据被复制到套接字,但并不意味着接收端获得数据。如果目标已关闭然后再上电,则必须从数据丢失数据的位置重新发送数据(在建立新的TCP连接之后)到副本。
让我们说我正在处理大量数据并且我不保留我已发送的数据(即write()系统调用返回成功)。我只保留要发送的待处理数据。
当副本从意外关闭中恢复并再次连接时,如何从内核获取已写入套接字但在目标主机上没有“确认”的数据呢? / p>
或者换句话说,如何从丢失TCP连接中恢复,并从客户端和服务器停止的位置重新建立传输?
答案 0 :(得分:2)
您需要在TCP之上添加另一级抽象。发送完每一段数据后(TCP保证它将完好无损地按顺序到达),让另一端的进程发送它自己的ACK,在你自己的更高级协议中(无论是什么 - 是它) ACK \ 0“,”GOT \ n“或其他任何内容)。另一方面(发起者),请阅读此数据。如果它没有错误就会变好,一切都很好。如果出现错误 - 请检查类型。如果你得到ECONNRESET,那意味着远程端已经死了。由此,您可以做出相应的回应。等到你可以重新连接,然后重复重复发送数据。
答案 1 :(得分:2)
无法通过标准API执行您想要的操作。
解决方案可能是让您的客户端定期发送回收到的已运行的字节总数并验证写入光盘,然后在服务器上保留已发送但未确认数据的缓冲区。然后,当客户端重新连接时,它会发送最后一次正常计数,服务器知道从哪里开始重新传输。
答案 2 :(得分:1)
TCP会处理TCP所需的序列号,你无法在应用程序级别上大量使用它们
您需要在应用程序级别进行一些序列控制。
在这种情况下,您可以为您发送的每个数据块分配一个数字。目的地需要持续跟踪它收到的最后一个块号。在意外关闭启动时,目标需要回传它处理的最后一个块号,然后从那里开始发送。
如何从内核获取已写入套接字的数据,但目标主机上还没有“确认”?
即使你可以,这还不够。目标主机可能已经很好地确认了数据,但无论出于何种原因,ack可能会丢失,或者从未发送过,但目标应用程序本可以接收并处理该数据。因此,如果在这种情况下使用TCP序列号,则最终会得到重复数据。
另一种情况是TCP发送了数据的ack,目标应用程序在读取数据时崩溃/关闭,但在将其写入磁盘之前。所以你最终会丢失数据。