用udp实现断点续传,采用滑动窗口,延时重发的思路

本文介绍了使用UDP协议通过滑动窗口和延时重发机制实现文件传输的过程,包括发送方的滑动窗口、延时重发逻辑,以及接收方的缓存、响应和断点续传机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不知有没有现成好用的类,有的话还请告诉我一声,先谢谢了!

这个例子仅供学习参考。我原来觉得使用udp应该会比tcp快一些,但是既然要延时重发,也就是要保证连接可靠性;既然要可靠,不如干脆用tcp得了,tcp在传输层实现了滑动窗口和流量及拥塞控制,直接用serverSocket 编程简单一点,实现多线程下载也方便



一、滑动窗口,延时重发:
我是这么实现的:其中用到了Thread.suspend()和resume()这些被Deprecated的方法,不过我用的时候倒是没出什么问题。
发送方Sender大概如下:实例域包括两个Thread和一个timer。代码因为和其他功能有些耦合,所以没有贴出来;这里只写个大概

public class Sender  extends ThreadGroup{
    private Thread t;//用来发送滑动窗口中的数据包
    private Thread r;//用来监听接收方的响应从而移动滑动窗口
    private javax.swing.Timer timer;//滑动窗口中的数据发送完后还没有接收到回应,就启动这个定时器,计时结束后从新发送滑动窗口中的数据
    public Sender(){
        t = new T(this,"t");
        r = new R(this,"r");
        timer = new Timer(2000,new ActionListener(){
            public void run(){
                t.resume();
            }
        }
    }
    public void join(){
        t.join();
        r.join();
    }
    private class T extends Thread{
        public void run(){
            while(!eof){
                while(要发送的数据包在滑动窗口范围中){//滑动窗口只不过是两个指针指向窗口的头和尾
                    datagramSocket.send(datagramPakcet);
                    已发送的长度 += 数据包长度;
                    Thread.sleep(100);
                }
                timer.start();
                suspend();
            }
        }
    }
    private class R extends Thread{
        public void run(){
            while(!eof){
                datagramSocket.receive(datagramPacket);
                接收到的packet中携带了接收方接收到了第几帧的信息,将移动窗口向前移动
                timer.stop();
                t.resume();
            }
        }
    }
}

timer中还可以设置一下,比如重发5次没有应答就终止线程

接收方Receiver:实例域包括一个HashMap和一个Stack
接收时从stack中取出一个缓冲区用来接收,若接收到的这一帧是我要的下一针,就写入文件;否则先放入hashmap,等要的下一帧到了在从hashmap中取出,按顺序一起写入文件,写完后把缓冲区放会到stack中。每接收几帧后像发送方回应一下接收到哪里了

public Receiver extends Thread{
    private HashMap map;
    private Stack stack;
    public void run(){
        while(!eof){
            byte buf = stack.pop();
            datagramPacket.setData(buf);
            datagramSocket.receive(datagramPacket);
            packet数据头携带有第几帧的信息
            if(该帧是在我的接收滑动窗口中){
                map.put(id,datagramPacket.getData());
                while((buf = map.remove(id++)) != null){
                    将buf写入文件;
                    stack.push(buf);
                }
            }
            每接收5个数据包后向发送方回应一下;
       }
    }
}


二、断点续传
接收方接收文件时可以创建两个同名文件,一个后缀".aaa",一个后缀".bbb",.aaa的就是正在接收的文件,为接收完成后在把后缀aaa去掉;.bbb的文件用来记录信息,接收过程中不断把接收到了第几个帧写入.bbb文件中。这样即使接收到一半程序终止,下一次只要读取这个文件就能知道上次接收到哪里,向发送方发出请求时让它从这里开始发送就行了


三、发送文件夹
不知为什么网络上很少见能发送整个文件夹的,只能打包在发送。
其实发送文件夹很简单:
public void sendDirctory(File dir){
    if(dir.isFile()){
        Sender sender = new Sender(dir);
        sender.start();
        sender.join();//用join,使发送完这个文件在发送下一个
    }
    else{
        File[] list = dir.list();
        for(int i=0;i<list.length;i++){
            sendDirectory(list[i]);    
        }
    }
}


四、ByteBuffer类:
ByteBuffer 可以对字节数组进行操作,可以从字节数组中读出和写入int,byte,long ,short等数据类型,和FileChannel配合使用挺方便的,就是要注意其中position 和 limit 指针的移动。
ByteBuffer 对读写数据包的包头信息很方便,byteBuffer.array()方法能转化成数组,然后用datagramPacket发送出去。

转载于:https://my.oschina.net/soitravel/blog/36146

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值