我正在使用基于 UDP (SOCK_DGRAM) 的 C++ 套接字开发客户端和服务器文件传输应用程序。对于 PUT 方法,我有以下执行(握手后):
客户端
Send a packet;
if time_out
send the packet again;
else //ack received
send a new packet;
服务器
wait for the first packet;
send acknowledge;
while(!EOF)
Get a packet;
Send an ack;
EOF 基本上是通过与我在握手期间发送的文件大小进行比较来检查我是否收到了整个文件。
在此交换过程中,数据包随时可能丢失。客户端可以发送丢失的数据包。它将在等待 ACK 时超时并重新发送数据包。服务器收到一个数据包并发送一个ACK。该 ACK 可能会丢失,此时客户端超时并重新发送他的数据包。由于这些数据包具有编号序列,我们可以忽略多次收到的数据包。
我的困惑发生在文件传输结束时。客户端刚刚发送了包含文件最后几位的数据包。服务器成功收到它并发送他的ACK。这个数据包丢失了。服务器应用程序现在处于 while 循环之外,因为他已将最后一位写入文件,并且从他的角度来看文件传输已成功。但是,客户端从未收到 ACK,因此超时并重新发送数据包。这里应该发生什么?服务器未监听或正在监听新请求,而不是数据。客户端或服务器应该在什么时候认为传输完成并停止尝试通信?
最佳答案
听起来您正在重新发明 TFTP ,但客户端和服务器角色向后。你确定你需要这样做吗?由于缺少滑动窗口或数据管道,这是一个非常低效的协议(protocol)。
我看到了 3 个解决您难题的方法:
- 文件传输结束时的三次握手。服务器收到最后一个数据 block 后,不仅发送ACK,还等待客户端确认ACK。发生这种情况时,服务器知道客户端知道文件传输已完成。如果服务器从未收到 ACK 的 ACK,它会定期重新发送它的最后一个数据 block 的 ACK。
- 服务器会在文件传输完成后记住几分钟(或几个 RTT,以较大者为准)。如果在那段时间里,它从客户端接收到任何数据 block ,用于本应已经完成的文件传输,则服务器只是确认它而不做任何事情,并重置该文件传输的传输结束计时器。这更复杂,但与之前的解决方案相比具有优势,即服务器能够在文件传输完成后继续执行其他工作。
- 如果服务器接收到任何不属于事件文件传输的数据 block ,它会以错误(NAK)作为响应。这适用于它是否属于不存在的、无效的或已经完成的传输。这是最简单的实现方式,但也是最难实现的,因为客户端在收到 NAK 时必须因错误而终止。但也许这没关系,因为从服务器的角度来看,文件传输仍然是成功的。
关于c++ - 停止并等待文件传输协议(protocol),什么时候停止监听?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9575417/