当前位置: 首页 > 知识库问答 >
问题:

具有并发多线程请求的Java OKHTTP SocketTimeoutException

祁杰
2023-03-14

我的Java应用程序使用各种代理服务器从特定域收集数据。特别申请需要下列程序:

  • 通过特定代理加载URL
  • 等待5秒
  • 通过同一个代理加载下一个url

为了使信息的加载(由于5秒的暂停)不需要永远,我总共使用400个线程。每个线程都使用自己的代理服务器,也就是使用自己的OKHTTP客户端:

MyHTTPClient = new OkHttpClient.Builder()
.connectTimeout(7, TimeUnit.SECONDS)
.writeTimeout(7, TimeUnit.SECONDS)
.readTimeout(7, TimeUnit.SECONDS)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ProxyIP, ProxyPort)))
.proxyAuthenticator((Route route, Response response) - > {
    return response.request().newBuilder().header("Proxy-Authorization", Credentials.basic(ProxyUser, ProxyPass)).build();
})
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((String hostname, SSLSession session) - > true)
.addNetworkInterceptor(new LoggingInterceptor())
.retryOnConnectionFailure(true)
.build();

每个线程必须使用自己的代理,因此每个线程都有自己的OKHTTP客户端。总共有400个OKHTTP客户端。

 while (true) {
     MyAnswer = MyHTTPClient.newCall(
         new Request.Builder().url(https://www.example.com)
         .addHeader("referer", SomeReferrer)
         .addHeader("cache-control", "no-cache")
         .addHeader("pragma", "no-cache")
         .get().build())
     .execute();

     Body = MyAnswer.body().string();
     MyAnswer.body().close();

     Thread.sleep(5000);
 }
java.net.SocketTimeoutException: connect timed out
at java.base/java.net.PlainSocketImpl.waitForConnect(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:107)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.base/java.net.Socket.connect(Socket.java:608)
at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:120)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
at okhttp3.internal.connection.RealConnection.connectTunnel(RealConnection.kt:261)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:201)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)

我做了一些研究,发现在并发连接方面可能存在某种限制。我发现,无论何时发生此错误,连接池中都没有空闲连接:

MyHTTPClient.connectionPool().idleConnectionCount() //Always 0 when the Timeout-Exception occurs

因此,我尝试为每个okhttpclient增加连接池的大小,但这似乎完全没有效果:

.connectionPool(new ConnectionPool(5000, 100, TimeUnit.MILLISECONDS))

我还尝试增加和减少httpclient的超时值,这实际上似乎会影响应用程序在没有此错误的情况下运行多长时间,但实际上并没有阻止这种情况的发生。

Dispatcher MyDispatcher = new Dispatcher(Executors.newCachedThreadPool());
MyDispatcher.setMaxRequests(9999999);
MyDispatcher.setMaxRequestsPerHost(9999999);

共有1个答案

姬衡
2023-03-14

首先创建一个OkHttpClient,然后使用OkHttpClient.newBuilder()自定义代理。这将导致客户端共享线程池和连接池。这可能不能解决你的问题,但它会使它更有效。

  final OkHttpClient sharedHttpClient = new OkHttpClient.Builder()
    .connectTimeout(7, TimeUnit.SECONDS)
    .writeTimeout(7, TimeUnit.SECONDS)
    .readTimeout(7, TimeUnit.SECONDS)
    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
    .hostnameVerifier((String hostname, SSLSession session) - > true)
    .addNetworkInterceptor(new LoggingInterceptor())
    .retryOnConnectionFailure(true)
    .build();
MyHTTPClient = sharedHttpClient.newBuilder()
    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ProxyIP, ProxyPort)))
    .proxyAuthenticator((Route route, Response response) - > {
    return response.request().newBuilder().header("Proxy-Authorization", Credentials.basic(ProxyUser, ProxyPass)).build();
})
    .build();
 类似资料:
  • 问题内容: 我过去两天一直在尝试构建具有多线程功能的刮板。不知何故我仍然无法管理它。最初,我尝试使用带有线程模块的常规多线程方法,但这并不比使用单个线程快。后来我了解到请求正在阻塞,并且多线程方法并没有真正起作用。因此,我不断研究并发现有关grequests和gevent的信息。现在,我正在使用gevent运行测试,它仍然没有比使用单个线程快。我的编码有误吗? 这是我课程的相关部分: 问题答案:

  • 我正在使用Rxjava2和Spring Boot。 我在服务器上有500个并发请求。 每个请求产生10个线程,这些线程调用其他服务(因此IO工作)

  • 我正在使用spring 和< code>HTTP post请求,逐行获取数据,然后将数据发送到API的HTTP请求中,这对我来说很好,但这里我使用的是大量数据,所以我必须使用多线程,但我是java和spring的新手,我如何实现使用10个线程,每个线程每次并行读取1k的数据? 我读过关于10个线程的多线程,其中每个线程每次读取1k行,我的数据库中有大约1000万条记录 访问DataJpaAppli

  • 并发是什么?引用Rob Pike的经典描述: 并发是同一时间应对多件事情的能力 其实在我们身边就有很多并发的事情,比如一边上课,一边发短信;一边给小孩喂奶,一边看电视,只要你细心留意,就会发现许多类似的事。相应地,在软件的世界里,我们也会发现这样的事,比如一边写博客,一边听音乐;一边看网页,一边下载软件等等。显而易见这样会节约不少时间,干更多的事。然而一开始计算机系统并不能同时处理两件事,这明显满

  • 本章讲解 Rust 中,并发,并行,多线程编程的相关知识。

  • 问题内容: 我使用Python Requests库下载一个大文件,例如: 大文件的下载速度为每秒+-30 Kb,这有点慢。与bigfile服务器的每个连接都受到限制,因此我想建立多个连接。 有没有一种方法可以同时建立多个连接来下载一个文件? 问题答案: 您可以使用HTTP标头仅获取文件的一部分(此处已涵盖python)。 只需启动几个线程,并获取每个线程的不同范围,就可以完成;) 还要注意,并非每