码迷,mamicode.com
首页 > 编程语言 > 详细

【Bug】httpClient使用代理后线程挂起

时间:2019-12-21 13:44:52      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:一个   res   size   爬取   exe   div   bug   为什么   style   

背景:

  需要去监控某个网站,所以写了一个爬虫程序,被爬取的链接是Https,使得的是网上的代理,按ip使用量计费,该计费模式确实好用!

  框架:httpClient 4.5.10

  Java: Java 9

implementation org.apache.httpcomponents:httpclient:4.5.10

问题:

  然后问题出现了,因为是一个监控程序,所以需要不断的轮询,然后开了10个左右线程轮询,结果跑了半小时后,10个线程全部刮起,thread dump一下发现每个线程都如下:

"http-nio-8081-exec-7@5795" daemon prio=5 tid=0x2a nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at java.net.SocketInputStream.socketRead0(SocketInputStream.java:-1)
      at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
      at java.net.SocketInputStream.read(SocketInputStream.java:171)
      at java.net.SocketInputStream.read(SocketInputStream.java:141)
      at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
      at sun.security.ssl.InputRecord.read(InputRecord.java:503)
      at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
      - locked <0x1c8d> (a java.lang.Object)
      at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:933)
      at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
      - locked <0x1c8e> (a sun.security.ssl.AppInputStream)
      at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
      at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
      at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)
      at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
      at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)

 

  WTF?一直卡在 java.net.SocketInputStream.socketRead0 方法上,难道是我没有设置超时逻辑?于是赶紧去查找代码,加上逻辑:

HttpClient httpClient = HttpClientBuilder.create()
                                             .setConnectionManager(connManager)
                                             .setConnectionTimeToLive(20000L, TimeUnit.MILLISECONDS)
                                             .setRetryHandler(getRetryHandler())
                                             .setDefaultCredentialsProvider(getProxyProvider())
                                             .build();

  

  自信的跑了一段时间后,无用还是挂着,于是上网看看,发现很多人都遇到过这种事,但没人说明是为啥?有几种可能:

  1. httpClient某个版本的bug,在某个版本后修复了,然后检查发现,我的版本是最新的,没问题
  2. 某博主也是用的代理,情况和我一摸一样,然后搞不出问题,所以就绕过去了,kill thread ,这真是神操作

解决:

  因为是用的是框架,对框架也不熟,所以直觉告诉我需要先考虑是框架的问题,所以开始对httpClient的使用开始研究,太恶心了,这个框架每个版本的使用方法都不太一样;最终我发现两种设置超时的方法,一个是掌控应用层的RequestConfig,第二种是掌控Socket的SocketConfig,这个时候我已经猜到了问题原因,这次信心慢慢,于是我加入了以下代码,发现问题神奇的解决了。

BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager();
    connManager.setSocketConfig(SocketConfig.custom().setSoTimeout(2000).build());
    HttpClient httpClient = HttpClientBuilder.create()
                                             .setConnectionManager(connManager)
                                             .setConnectionTimeToLive(20000L, TimeUnit.MILLISECONDS)
                                             .setRetryHandler(getRetryHandler())
                                             .setDefaultCredentialsProvider(getProxyProvider())
                                             .build();

分析:

  抱着知其所以然的心态,为什么还需要加上这个配置呢?我开始深思研究他们的源码:

【Bug】httpClient使用代理后线程挂起

标签:一个   res   size   爬取   exe   div   bug   为什么   style   

原文地址:https://www.cnblogs.com/iCanhua/p/12076636.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!