2012-03-05 39 views
3

我正在开发客户端和服务器文件传输应用程序与UDP套接字(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,因此超时并重新发送数据包。这里应该发生什么?服务器不在侦听或正在侦听新请求,而不是数据。客户端或服务器应该在什么时候认为传输已完成并停止尝试进行通信?

回答

2

听起来你正在重塑TFTP,但客户端和服务器角色倒退了。你确定你需要这样做吗?由于缺乏滑动窗口或数据管道,这是一个非常低效的协议。

我看到3个解决方案,您的难题:

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

我认为对于你的第一个解决方案,我会遇到同样的问题[Generals](http://en.wikipedia.org/wiki/Two_Generals%27_Problem)。客户端和服务器反转他们的角色,但不知道对方是否收到了,无论数据包是否丢失。对于你的第二种解决方案,这就是我想要做的,但现在我必须记住序列号或某种类型的会话ID,以知道数据包不属于。如果客户没有收到这些确认(在不合理的情况下,比如超过60%的掉话率),这仍然不会阻止客户继续发送。我认为3rd是最好的选择。 – 2012-03-05 23:35:54

+0

对于第一种解决方案,您对无限回归完全正确。好点子。在实践中,我猜你会在客户离开后长时间停顿后放弃服务器。对于第二种解决方案,你是对的,你需要更多的状态。我不确定,但我怀疑TFTP PUT操作有点像这个解决方案。 – Celada 2012-03-05 23:53:46

1

明显的解决办法是防止服务器之后立即听。我会让服务器不断发送一个特殊的数据包,其数值代表end of file,直到从客户端收到确认。

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

+0

这是为了实践,了解确认交互背后的原则。 – 2012-03-05 23:30:08

+0

够公平的,我很佩服。总是很高兴知道更高水平的系统如何在发动机罩下工作 – 2012-03-05 23:32:50

+0

感谢您通过哈哈跟踪。 – 2014-04-10 18:30:32