于是我看了看nutch的源代码。因为我配置的nutch抓取很正常。哈哈,原来nutch也是采用的HttpClient。于是我照搬了他的这部分代码。运行正常。没在出现死锁。我估计可能是由于对MultiThreadedHttpConnectionManager的一些配置参数设置的不够合理。至于具体原因我也没弄明天,因为最开始我自己写的代码没被保留下来。也就无法分析了。下面我把这个类的实现代码贴出来,以供有需要的朋友采用。package org.flaviotordini.arale;import java.util.ArrayList;import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.protocol.Protocol;public class Http {
private static MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
// Since the Configuration has not yet been setted,
// then an unconfigured client is returned.
private static HttpClient client = new HttpClient(connectionManager);
private static Http http = new Http(); static synchronized HttpClient getClient() {
return client;
} private Http() {
configureClient();
} public static Http getInstance() {
return http;
} private void configureClient() {
int maxThreadsTotal = 30;
int maxThreadsPerHost = 3;
// Set up an HTTPS socket factory that accepts self-signed certs.
Protocol dummyhttps = new Protocol("https",
new DummySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", dummyhttps); HttpConnectionManagerParams params = connectionManager.getParams();
params.setConnectionTimeout(10 * 1000);
params.setSoTimeout(10 * 1000);
// params.setSendBufferSize(BUFFER_SIZE);
// params.setReceiveBufferSize(BUFFER_SIZE);
params.setMaxTotalConnections(maxThreadsTotal);
if (maxThreadsTotal > maxThreadsPerHost) {
params.setDefaultMaxConnectionsPerHost(maxThreadsPerHost);
} else {
params.setDefaultMaxConnectionsPerHost(maxThreadsTotal);
} HostConfiguration hostConf = client.getHostConfiguration();
ArrayList headers = new ArrayList();
// prefer English
headers.add(new Header("Accept-Language",
"en-us,zh-cn,zh-tw,en-gb,en;q=0.7,*;q=0.3"));
// prefer UTF-8
headers.add(new Header("Accept-Charset",
"big5,gb2312,gbk,utf-8,ISO-8859-1;q=0.7,*;q=0.7"));
// prefer understandable formats
headers
.add(new Header(
"Accept",
"text/html,application/xml;q=0.9,application/xhtml+xml,text/xml;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"));
// accept gzipped content
headers.add(new Header("Accept-Encoding", "x-gzip, gzip"));
hostConf.getParams().setParameter("http.default-headers", headers);
// if (useProxy) {
// hostConf.setProxy(proxyHost, proxyPort);
// }
// if (ntlmUsername.length() > 0) {
// Credentials ntCreds = new NTCredentials(ntlmUsername, ntlmPassword,
// ntlmHost, ntlmDomain);
// client.getState().setCredentials(
// new AuthScope(ntlmHost, AuthScope.ANY_PORT), ntCreds);
//
// if (LOG.isInfoEnabled()) {
// LOG.info("Added NTLM credentials for " + ntlmUsername);
// }
// }
// if (LOG.isInfoEnabled()) {
// LOG.info("Configured Client");
// }
}
}然后在你采集线程实现中
GetMethod get = new GetMethod(url);
Http http = Http.getInstance();
HttpClient client = http.getClient();;
int result = client.executeMethod(get);
............
记住要调用get.releaseConnection();关闭连接。还需要在废话点儿。你在读取流的时候直接读取字节然后封装到字节数组里面。而不要采用StreamReader来封装。理由是你采集的网站的编码是不确定的。你可以用默认字符编码把字节数组转换为字符串,通过正则表达式从<meta....>中取出字符编码。但也有些网页这样是取不到编码信息的,这里我是采用的org.mozilla.intl.chardet这个开源实现包。在http://codesearch.google.com上可以搜索到源码。