一个基于NIO的下载队列实现

package l.test1.queue.nio;

import java.io.File;

public interface Task {
	public String getNetWorkPath();
	
	public String getName();
	/**
	 * 
	 * @param file
	 */
	public void success(File file);
	/**
	 * 
	 * @param netWorkPath
	 */
	public void fail(String netWorkPath);
}

package l.test1.queue.nio;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class NIODownLoad extends Thread {
	private boolean run = true;
	private static final int DOWN_LOAD_MAX_COUNT = 10;
	private int downLoadCount = 0;
	private Selector selector = null;
	private Queue<Task> queue = new LinkedList<Task>();

	private NIODownLoad() {
		setDaemon(true);
		try {
			selector = Selector.open();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static final NIODownLoad instance = new NIODownLoad();
	
	static{
		instance.start();
	}
	
	public static NIODownLoad getInstance() {
		return instance;
	}

	@Override
	public void run() {
		SelectionKey key = null;
		while (run) {
			try {
				if(selector.select() <=0 ){
					success();
					continue;
				}
				for (Iterator<SelectionKey> iter = selector.selectedKeys()
						.iterator(); iter.hasNext();) {
					key = iter.next();
					iter.remove();
					if (key.isConnectable()) {
						connect(key);
					} else if (key.isReadable()) {
						read(key);
					} else if (key.isWritable()) {
						write(key);
					}
				}
			} catch (IOException e) {
				if(null != key) {
					key.cancel();
					key = null;
					downLoadCount --;
				}
				e.printStackTrace();
			}
		}
	}

	public void add(Task task) {
		synchronized (queue) {
			File file = new File(DownLoadSession.basePath+"/"+task.getName());
			if(file.exists()) {
				task.success(file);
				return;
			}
			if(queue.contains(task)) {
				System.out.println("exist");
				return;
			}
			queue.add(task);
			if(downLoadCount < DOWN_LOAD_MAX_COUNT) {
//				instance.interrupt();
				selector.wakeup();
			}
		}
	}


	private void connect(SelectionKey key) throws IOException {
		SocketChannel client = (SocketChannel) key.channel();
		if (client.finishConnect()) {
			Task task = (Task) key.attachment();
			client.register(selector, SelectionKey.OP_WRITE,new DownLoadSession(client, task));
		}
	}

	private void read(SelectionKey key) throws IOException {
		DownLoadSession session = (DownLoadSession) key.attachment();
		if (session.read() == -1) {
			downLoadCount --;
			success();
			key.cancel();
		}
	}

	private void write(SelectionKey key) throws IOException {
		DownLoadSession session = (DownLoadSession) key.attachment();
		if (session.write() == -1) {
			key.interestOps(SelectionKey.OP_READ);
		}
	}
	
	private void success() {
		if(downLoadCount < DOWN_LOAD_MAX_COUNT) {
			synchronized (queue) {
				if(!queue.isEmpty()) {
					System.out.println("success");
					Task task = queue.poll();
					URL url;
					try {
						url = new URL(task.getNetWorkPath());
						int port = url.getPort();
						if(-1 == port) {
							port = 80;
						}
						InetSocketAddress remote = new InetSocketAddress(url.getHost(),port);
						try {
							SocketChannel socket = SocketChannel.open();
							socket.configureBlocking(false);
							socket.connect(remote);
//							socket.finishConnect();
							socket.register(selector, SelectionKey.OP_CONNECT, task);
							downLoadCount ++;
						} catch (IOException e) {
							e.printStackTrace();
						}
					} catch (MalformedURLException e1) {
						e1.printStackTrace();
					}
				}
			}
		}
	}

	public static void main(String[] args) throws Exception{
		NIODownLoad down = new NIODownLoad();
//		for(int i=0;i<10000;i++) {
			Task task = new T("http://www.baidu.com/img/baidu_sylogo1.gif");
			down.add(task);
			down.add(new T("http://www.google.com.hk/intl/zh-CN/images/logo_cn.png"));
//		}
		down.start();
//		down.add(new T("http://www.google.com.hk/intl/zh-CN/images/logo_cn.png"));
		
//		Task task = new T("http://www.google.com.hk/intl/zh-CN/images/logo_cn.png");
//		Task task = new T("http://www.google.com.hk/intl/zh-CN/images/logo_cn.png");
//		Task task = new T("http://www.google.com.hk/intl/zh-CN/images/logo_cn.png");
//		System.out.println(new URL("http://www.google.com.hk").getPath());
	}
}

class T implements Task {
	private String url;
	private String name;
	T(String url) {
		this.url = url;
		String n = "";
		try {
			URL u = new URL(url);
			String path = u.getPath();
			if(path.length() == 0) {
				n = "/index.html";
			}else {
				int p = path.lastIndexOf('/');
				if(p != -1) {
					n = path.substring(p);
				}
//				n = path;
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
//		name = System.currentTimeMillis()+"_"+((int)(Math.random() * 1000))+"_"+n;
		name = n;
	}
	@Override
	public String getNetWorkPath() {
		return url;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void success(File file) {
		System.out.println(file.getAbsolutePath());
	}

	@Override
	public void fail(String netWorkPath) {
		System.out.println("ERROR   "+ netWorkPath);
	}
	
}

package l.test1.queue.nio;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class DownLoadSession {

	public static final String basePath = new File("/sdcard/test/photos/").getAbsolutePath();
	private int bufSize = 512;
	private SocketChannel client;
	private Task task;
	private ByteBuffer buf;
	private FileChannel fileChannel;
	private File file;
	private boolean headEnd = false;
	private byte[] headCheckCache = new byte[4];
	private int headCheckIndex = 0;
	
	private ByteBuffer head;
	private File newFile;
	
	public DownLoadSession(SocketChannel client, Task task) {
		this.client = client;
		this.task = task;
		buf = ByteBuffer.allocate(bufSize);
		try {
			newFile = new File(basePath + "/" + task.getName());
			file = new File(basePath +"/"+task.getName()+".data");
			if(!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			fileChannel = new FileOutputStream(file).getChannel();
			builderHead();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	private void builderHead() {
		try {
			URL url = new URL(task.getNetWorkPath());
			String host = url.getHost();
			String path = url.getPath();
			if(path.length() == 0) {
				path = "/";
			}
			String query = url.getQuery();
			StringBuilder builder = new StringBuilder("GET ")
			.append(String.format("%s%s%s", path,null==query?"":"?",null==query?"":query))
			.append(" HTTP/1.1\r\nHOST: "+host+"\r\nConnection: close\r\n\r\n");
			head = ByteBuffer.wrap(builder.toString().getBytes());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
	}
	
	public int read() throws IOException{
		try{
			int readBytes = client.read(buf);
			if(readBytes > 0) {
				buf.flip();
				if(headEnd) {
					fileChannel.write(buf);
				} else {
					readHead();
					if(buf.hasRemaining()) {
						fileChannel.write(buf);
					}
				}
				buf.compact();
			}else if(readBytes == -1) {
				fileChannel.close();
				file.renameTo(newFile);
				task.success(newFile);
			}
			return readBytes;
		}catch(IOException e){
			fileChannel.close();
			file.delete();
			throw e;
		}
	}

	private void readHead() {
		while(buf.hasRemaining() && !headEnd) {
			byte b = buf.get();
//			if(headCheckIndex == 3) {
//				for(int i=0;i<headCheckIndex;i++) {
//					headCheckCache[i] = headCheckCache[i+1]; 
//				}
//			}
			headCheckCache[headCheckIndex] = b;
			headEnd = checkHead();
			if(headEnd) {
				break;
			}
			if(headCheckIndex < 3) {
				headCheckIndex ++;
			}
			else {
				headCheckIndex = 0;
			}
			
		}
	}

	private boolean checkHead() {
		int i = Math.abs(headCheckIndex - 3);
//		int i = 0;
		return headCheckCache[i++ % 4] == '\r' && headCheckCache[i++ % 4] == '\n' 
				&& headCheckCache[i++ % 4] == '\r' && headCheckCache[i % 4] == '\n';
	}

	public int write() throws IOException{
		if(null != client && null != head && head.hasRemaining()) {
			return client.write(head);
		}
		return -1;
	}

}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值