WebClient在多线程、使用代理情况下 socket closed 问题的一个解决办法[htmlunit]

通过 WebClient 的内置浏览器,可以执行页面抓取工作,有时可能需要设置代理,
WebClient webClient = new WebClient(BrowserVersion.x);
webClient.setProxyConfig(ProxyConfig pc);
在单线程情况下,使用这样创建的webClient不会有问题:客户端到代理服务器的连接能够很有次序的建立、关闭。

考虑这样的情况:多个线程并发地访问 WebClient,可能就会报下面的异常:

[Thread-7] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Closing connection [HttpRoute[{}->http://192.168.5.29:3128->http://58.223.139.151:8080]][null]
........
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Total connections kept alive: 0
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Total issued connections: 0
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Total allocated connection: 0 out of 20
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - No free connections [HttpRoute[{}->http://192.168.5.29:3128->http://58.223.139.151:8080]][null]
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Available capacity: 2 out of 2 [HttpRoute[{}->http://192.168.5.29:3128->http://58.223.139.151:8080]][null]
2012-04-19 10:31:32,926 [Thread-8] DEBUG org.apache.http.impl.conn.tsccm.ConnPoolByRoute  - Creating new connection [HttpRoute[{}->http://192.168.5.29:3128->http://58.223.139.151:8080]]
2012-04-19 10:31:32,926 [Thread-6] DEBUG org.apache.http.impl.client.DefaultHttpClient  - socket closed
java.net.SocketException: socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:130)
at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:127)
at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:233)
at org.apache.http.impl.conn.LoggingSessionInputBuffer.readLine(LoggingSessionInputBuffer.java:100)
at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:98)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:210)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:271)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:227)
at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:209)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:292)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:126)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:483)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:597)
at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:134)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1406)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1460)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1325)

at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:304)

at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:370)

异常信息显示:thread-6使用webclient时,检测到 socket closed异常,查看上面的异常,存在 socket (http://192.168.5.29:3128->http://58.223.139.151:8080)被 thread-7 关闭的情况,thread-8 创建了新 socket,可能之后某个时间点,socket又被关闭,导致 thread-6 报socket closed异常。
通过使用ThreadLocal为不同的线程创建各自独立的 WebClient 对象,就能避免上述问题:

[java] view plaincopy

    1. // 每个线程保持一个独立的 WebClient 对象,防止线程共用一个浏览器相互干扰
    2. private ThreadLocal<WebClient> client = new ThreadLocal<WebClient>() {
    3. protected synchronized WebClient initialValue(){
    4. WebClient webClient = new WebClient(version);
    5. //设置webClient的相关参数
    6. webClient.set...;
    7. return webClient;
    8. }
    9. };
    10. public void setWebClient(WebClient wc) {
    11. client.set(wc);
    12. }
    13. public WebClient getWebClient() {
    14. return client.get();
    15. }
时间: 2024-08-14 06:54:29

WebClient在多线程、使用代理情况下 socket closed 问题的一个解决办法[htmlunit]的相关文章

在数据库并发情况下避免插入重复数据的一个解决方法

目前公司的项目中碰到一个情况:需要向一个数据表table1中插入记录,该表的结构类似于下面的定义: 列名  类型 是否允许为空 Id int no Area string no AreaIndex int no Name string no 其中Name的值由Area和AreaIndex拼接而成,形式类似于“Area+AreaIndex”.对于相同的Area,AreaIndex从1开始计数,所以对于Area分别为“AA”,“BB”,“CC”的情况,Name的值类似下面这样: AA001 AA00

ARC 下处理内存暴涨的一个解决办法

有一种情况: for (int i = 0; i < 1000000000; i++) { NSString *s = @"ABC"; s = [s lowercaseString]; s = [s stringByAppendingString:@"ac"]; NSLog(@"%@", s); } 运行, 内存暴涨!!!!!! 这情况下, 给循环体里面的操作加一个 释放池 即可 for (int i = 0; i < 1000000

威联通212P 在admin用户密码正确情况下仍然无法登录WEB页面解决办法

*登录 telnet 执行以下语句: [~] # cp /etc/default_config/passwd /mnt/HDA_ROOT/.config/passwd[~] # cp /etc/default_config/shadow /mnt/HDA_ROOT/.config/shadow [~] # reboot

Nodejs发送Post请求时出现socket hang up错误的解决办法

参考nodejs官网发送http post请求的方法,实现了一个模拟post提交的功能.实际使用时报socket hang up错误. 后来发现是请求头设置的问题,发送选项中需要加上headers字段信息(这个估计也和对方的服务器有关,对于不完成的post请求头,可能被丢弃了). 完整的代码如下(遇到类型问题的同学可以做个参考): var querystring = require('querystring') , http = require('http'); var data = query

html页面顶部出现一段空白,检查控制台发现body 下出现&amp;#65279字符,原因及解决办法

html页面顶部出现一段空白,检查控制台发现body 下出现&#65279字符,原因及解决办法 分析: 原来是页面编码时增加了BOM,此页面后端数据主要是PHP语言,对PHP来讲PHP在设计时没有考虑BOM问题,,不会忽略UTF-8编码的文件开头BOM的那三个字符,会把BOM作为该文件开头正文的一部分.由于必须在<?或者<?php后面的代码才会作为PHP代码执行,所以将会造成在页面上输出这三个字符,显示效果就要看浏览器了,一般是一个空行或是一个乱码.由于在html一开头有这3个字符的存

Git服务器代理上网安装出现问题的几个解决办法。

1.gem安装出现下面错误 [email protected]:/home/git/gitlab# sudo gem install bundler --no-ri --no-rdoc ERROR:  Could not find a valid gem 'bundler' (>= 0), here is why: Unable to download data from https://rubygems.org/ - Errno::ETIMEDOUT: Connection timed out

windows下mysql忘记root密码的解决办法

今天早上 一朋友说自己的mysql 忘记root密码了 让我帮忙给看看,因为没有接触过mysql 所以从网上找了一下信息经我亲身实践  已经成功!mysql版本是5.1以下是从网上找的信息: 1. 首先检查mysql服务是否启动,若已启动则先将其停止服务,可在开始菜单的运行,使用命令: net stop mysql 打开第一个cmd1窗口,切换到mysql的bin目录,运行命令: mysqld --defaults-file="C:\Program Files\MySQL\MySQL Serve

mac 安装mysql 报错“ERROR 2002 (HY000): Can not connect to local MySQL server through socket &#39;/tmp/mysql.sock&#39; (2)” 解决办法

首先安装 homebrew 再 brew install mysql 之后连接 mysql 无论是登录还是修改初始密码都会报如下的错误 ERROR 2002 (HY000): Can not connect to local MySQL server through socket '/tmp/mysql.sock' (2) 运行如下解决:参考 http://www.thinksaas.cn/group/topic/347978/ unset TMPDIR mysql_install_db --v

Android项目中gen文件下R文件无法生成的解决办法

帮一个网友解决R文件无法生成的问题,搜集了些材料特整理如下,初学者参考他人代码时极易出现此种问题,一般都是xml文件出错,无法被正确解析. gen目录无法更新,或者gen目录下的R.JAVA文件无法生成 1.gen目录的用处 android gen目录下的R.java并不是由用户创建,而是android工程本身将android的资源进行自动"编号"(ID)值. 2.gen目录下R文件无法更新/生成的原因 1)res目录下的layout下的xml文件名有错.按照android的命名规范是