停止并等待文件传输协议,何时停止侦听



我正在开发一个客户端和服务器文件传输应用程序,该应用程序使用UDP上的C++套接字(SOCK_DGRAM)。对于PUT方法,我有以下执行(在握手之后):

client

Send a packet;
if time_out
    send the packet again;
else  //ack received
    send a new packet;

server

wait for the first packet;
send acknowledge;
while(!EOF)
    Get a packet;
    Send an ack;

EOF基本上是通过与握手期间发送的文件大小进行比较来检查我是否收到了整个文件。

在交换过程中,数据包随时可能丢失。客户端可以发送丢失的数据包。它将超时等待ACK并重新发送数据包。服务器接收数据包并发送ACK。该ACK可能会丢失,此时客户端超时并重新发送他的数据包。由于这些数据包有一个编号序列,我们可以忽略多次收到的数据包。

我的困惑发生在文件传输的最后。客户端刚刚发送了包含文件最后几位的数据包。服务器成功地接收到它并发送他的ACK。这个数据包丢失了。服务器应用程序现在处于while循环之外,因为他已经将最后一位写入了文件,并且从他的角度来看,文件传输是成功的。然而,客户端从未接收到ACK,因此超时并重新发送数据包。这里应该发生什么?服务器未在侦听或正在侦听新请求,而不是数据。客户端或服务器应该在什么时候考虑传输完成并停止尝试通信?

这听起来像是在重新发明TFTP,但客户端和服务器角色是向后的。你确定你需要这样做吗?由于缺少滑动窗口或数据管道,这是一个非常低效的协议。

我看到了3个解决你难题的方案:

  • 文件传输结束时的三方握手。在接收到最后一个数据块之后,服务器不仅发送ACK,而且等待客户端确认ACK。当这种情况发生时,服务器知道客户端知道文件传输已经完成。如果服务器从未接收到ACK的ACK,则它周期性地重新发送其最后数据块的ACK
  • 服务器会在文件传输完成后的几分钟内记住已完成的文件传输(或几个RTT,以较大者为准)。如果在这段时间内,服务器从客户端接收到本应已经完成的文件传输的任何数据块,则服务器只会确认该数据块,而不执行任何操作,并重置该文件传输的传输结束计时器。这更为复杂,但与以前的解决方案相比具有优势,即服务器可以在文件传输完成后继续运行并执行其他工作
  • 如果服务器接收到任何不属于活动文件传输的数据块,则服务器将以错误(NAK)进行响应。这适用于它是否是不存在的、无效的或已经完成的转移的一部分。这是实现起来最简单的,但也是最丑陋的,因为客户端在收到NAK时必须以错误终止。但也许这没关系,因为从服务器的角度来看,文件传输仍然是成功的

显而易见的解决方案是而不是阻止服务器立即侦听。我会让服务器不断发送一个特殊的数据包,其值表示end of file,直到收到来自客户端的确认。

您是否考虑过使用已经实现这种UDP文件传输的库,例如Raknet?这可能会让你的生活更轻松,因为你在这里重新发明轮子。

最新更新