Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何确保我的HttpClient 4.1不会泄漏套接字?_Java_Http_Sockets_Httpclient - Fatal编程技术网

Java 如何确保我的HttpClient 4.1不会泄漏套接字?

Java 如何确保我的HttpClient 4.1不会泄漏套接字?,java,http,sockets,httpclient,Java,Http,Sockets,Httpclient,我的服务器使用来自内部web服务的数据,根据每个请求构造其响应。我正在使用ApacheHttpClient 4.1发出请求。每个初始请求将导致对web服务的大约30个请求。其中,4-8个插座将被卡在CLOSE_WAIT中,永远不会释放。最终,这些被卡住的套接字超过了我的ulimit,我的进程耗尽了文件描述符 我不想仅仅提高我的ulimit(1024),因为这只会掩盖问题 我转到HttpClient的原因是java.net.HttpUrlConnection的行为方式与此相同 我已经尝试过为每个请

我的服务器使用来自内部web服务的数据,根据每个请求构造其响应。我正在使用ApacheHttpClient 4.1发出请求。每个初始请求将导致对web服务的大约30个请求。其中,4-8个插座将被卡在CLOSE_WAIT中,永远不会释放。最终,这些被卡住的套接字超过了我的ulimit,我的进程耗尽了文件描述符

我不想仅仅提高我的ulimit(1024),因为这只会掩盖问题

我转到HttpClient的原因是java.net.HttpUrlConnection的行为方式与此相同

我已经尝试过为每个请求移动到SingleClientConnManager,并对其调用client.getConnectionManager().shutdown(),但套接字仍然被卡住

我是否应该尝试解决这个问题,以便在没有运行请求的情况下得到0个打开的套接字,还是应该专注于请求持久性和池

为清楚起见,我将包括一些可能相关的细节:

操作系统:Ubuntu 10.10

JRE:1.6.0_22

语言:Scala 2.8

示例代码:

val cleaner = Executors.newScheduledThreadPool(1) 
private val client = {
    val ssl_ctx = SSLContext.getInstance("TLS")
    val managers = Array[TrustManager](TrustingTrustManager)
    ssl_ctx.init(null, managers, new java.security.SecureRandom())
    val sslSf = new org.apache.http.conn.ssl.SSLSocketFactory(ssl_ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
    val schemeRegistry = new SchemeRegistry()
    schemeRegistry.register(new Scheme("https", 443, sslSf))
    val connection = new ThreadSafeClientConnManager(schemeRegistry)
    object clean extends Runnable{ 
        override def run = {
            connection.closeExpiredConnections
            connection.closeIdleConnections(30, SECONDS)
        }
    }
    cleaner.scheduleAtFixedRate(clean,10,10,SECONDS)
    val httpClient = new DefaultHttpClient(connection)
    httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), new UsernamePasswordCredentials(username,password))
    httpClient
}
val get = new HttpGet(uri)
val entity = client.execute(get).getEntity
val stream = entity.getContent
val justForTheExample = IOUtils.toString(stream)
stream.close()
测试:netstat-a | grep{myInternalWebServiceName}grep CLOSE|u WAIT

(列出处于关闭等待状态的进程套接字)

评论后讨论:


此代码现在演示了正确的用法。

需要主动从连接池中清除过期/空闲的连接,因为在阻塞I/O模型中,除非从中读取/写入I/O事件,否则连接无法对I/O事件作出反应。详情请参阅


我已将oleg的回答标记为正确,因为它突出了HttpClient连接池的一个重要使用点

不过,为了回答我最初的特定问题,我应该尝试解决0个未使用的套接字,还是尝试最大化池

现在池解决方案已经就位并正常工作,应用程序吞吐量增加了约150%。我认为这是因为不必重新协商SSL和多次握手,而是根据HTTP 1.1重用持久连接


按照预期使用池是绝对值得的,而不是尝试在每次请求后调用ThreadSafeClientConnManager.shutdown()等等。另一方面,如果你调用任意主机,而不是像我这样重用路由,你可能会很容易发现有必要进行这种黑客行为,如果您不经常进行垃圾收集,JVM可能会让您惊讶于指定套接字的长使用寿命。

我遇到了同样的问题,并使用此处的建议解决了它:。作者介绍了一些TCP基础知识:

当TCP连接即将关闭时,其最终确定由双方协商。把它看作是以文明的方式违反合同。双方都签了字,一切都好。在极客对话中,这是通过FIN/ACK消息完成的。甲方发送一条FIN消息,表明其想要关闭套接字。乙方发送ACK,表示其已收到该消息并正在考虑该需求。然后乙方进行清理并向甲方发送FIN。甲方回复ACK,所有人都走开

问题来了 当B不发送它的鳍时。A有点等不及了。它有 已启动其最终确定序列,正在等待另一方 做同样的事

然后,他建议设置一个http头来解决这个问题:

postMethod.addHeader("Connection", "close");

老实说,我真的不知道设置此标题的含义。但是它确实阻止了我的单元测试发生CLOSE_WAIT。

谢谢你的回答,我同意文档中建议这应该是一种有效的措施。但是,随着脱离线程清理器的实现,孤立到CLOSE_WAIT中的套接字数量仍在可靠地增长,因此它并没有发挥作用。我已经在我的问题中添加了一些实现细节。我放弃了。我没有意识到,在实际的应用程序代码中,我正在发出补充图像请求以执行业务逻辑。他们仍然在使用HttpClient引入之前的WS.url方法,并且留下了套接字。断开的链接。(请包含标题和说明以及链接。)也许这是相同的信息?如果其他人偶然发现了这一点:相关API在HttpClient 4.2和4.3之间发生了变化: