爬虫(三)-NIO下载服务NIOFetcher的设计

       之前写的一个爬虫下载部分使用HttpClient,效率相当不敢恭维,最近打算使用NIO实现该部分,记录一下设计及实现过程中遇到的的问题。

一.基本思路

        以下为可能会犯的错误

         1.连接到同一服务器的SocketChannel数量过多

            看到很多人用SocketChannel模拟Http请求实现方式几乎都是为每一个域名下的URL注册一个SocketChannel,这种方式有一个弊端,不论从横向(多域名)还是纵向(同一域名),SocketChannel的总量不好控制,这就使我们很难在带宽与下载效率上进行权衡。

          2.频繁的打开、关闭SocketChannel

             我们很期望从本机到远程服务器能够建立几个相对稳定的长连接,以减少频繁打开、关闭Socket连接的资源消耗,但是还有另外一个问题:我们需要礼貌爬取,即使你选择"疯狂"爬取,也要考虑远程服务器强制关闭Socket连接的问题。权衡一下,我更倾向于使Socket可以保持一定时间的连接(可以叫做半长连接),打开一定时间的Socket连接在完成最后一次下载任务后就要关闭。

    

综合以上两个因素,我选择为同一域名的URL注册一定数量的(可配置,以适应下载服务器的性能与带宽的变动)Socket连接,以该值为阀值并辅以Socket连接服务时长对Socket连接数量进行横向与纵向的控制。


二.设计

   主要结构如下图所示:

                                         

其中IURLRegister与IFetchedURLHandler分别供爬行模块与文件持久化模块调用。


三.主要接口及实现类代码

         

package com.crazygeeker.search.fetcher;
/**
 * A service designed for download remote file.
 * <p>Provide basic operations such as <tt>start</tt><tt>shutdown</tt></p> 
 * @author JohnWang
 * @version 1.0
 * @date 2013-11-11
 */
public interface IFetcher {

	void start();
	
	void shutdown();
}


package com.crazygeeker.search.fetcher;

import com.crazygeeker.search.common.model.URLBean;
/**
 * register the url waiting for downloading
 * 
 * @author JohnWang
 * @version 1.0
 * @date 2013-11-11
 */
public interface IURLBeanRegister {
	/**
	 * 
	 * @param urlBean
	 * @return
	 */
	boolean register(URLBean urlBean);
}


package com.crazygeeker.search.fetcher;

import com.crazygeeker.search.common.model.URLBean;
/**
 * An interface for data upload
 * @author JohnWang
 * @version 1.0
 * @date 2013-11-11
 */
public interface IFetchedURLHandler {

	URLBean getURLBean();
}

          


package com.crazygeeker.search.fetcher;

import java.io.IOException;
import java.nio.channels.Selector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import com.crazygeeker.search.common.model.URLBean;
import com.crazygeeker.search.common.utils.LoggerUtils;
/**
 * 
 * @author JohnWang
 * @version 1.0
 * @date 2013-11-11
 */
public abstract class AbstractNIOFetcher implements IFetcher {

	protected Selector selector;
	/**
	 * 
	 */
	protected AtomicBoolean isRunning = new AtomicBoolean(false);
	/**
	 * 
	 */
	protected BlockingQueue<URLBean> pendingQueue = new PriorityBlockingQueue<URLBean>(); 
	/**
	 * 
	 */
	protected BlockingQueue<URLBean> fetchedQueue = new LinkedBlockingQueue<URLBean>();
	
	/**
	 * 
	 */
	public void start() {
		try {
			selector = Selector.open();
		} catch (IOException e) {
			e.printStackTrace();
			LoggerUtils.fetcherLogger.error("error.cannot_open_selector",e);
		}
		isRunning.set(true);
		LoggerUtils.fetcherLogger.info("selector has bean opened");
		service();
	}

	protected abstract void service();
	/**
	 * 
	 */
	public void shutdown(){
		try {
			selector.close();
		} catch (IOException e) {
			e.printStackTrace();
			LoggerUtils.fetcherLogger.error("error.cannot_close_selector",e);
		}
		LoggerUtils.fetcherLogger.info("selector has bean closed");
	}

}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值