简体   繁体   English

Java嵌入式HttpServer:套接字泄漏

[英]Java embedded HttpServer: socket leak

I have next proxy handler (used embedded HttpServer and Jersey client): 我有下一个代理处理程序(用于嵌入式HttpServer和Jersey客户端):

@Override
public void handle(HttpExchange httpExchange) throws IOException {
    ....
    ....
            WebTarget webTarget = httpClientHolder.getClient().target(url);
            try (Response response = webTarget.request().get()) {
                if (response.getStatusInfo().getStatusCode() != HttpStatus.SC_OK) {
                    logger.warn("Failed to download resource, url = " + url + " code = " +
                            response.getStatusInfo().getStatusCode());
                    throw new HttpException("Not found", 404);
                }
                httpExchange.sendResponseHeaders(200, response.getLength());
                final InputStream is = response.readEntity(InputStream.class);
                try (final OutputStream os = httpExchange.getResponseBody()) {
                    IOUtils.copy(is, os, 128);
                } catch (IOException e) {
                    logger.warn("Error proxy data", e);
                }
            }
    ....
}

sometimes the following happens 有时发生以下情况

Error proxy data
java.io.IOException: Broken pipe
        at sun.nio.ch.FileDispatcherImpl.write0(Native Method) ~[?:1.8.0_191]
        at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47) ~[?:1.8.0_191]
        at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93) ~[?:1.8.0_191]
        at sun.nio.ch.IOUtil.write(IOUtil.java:65) ~[?:1.8.0_191]
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471) ~[?:1.8.0_191]
        at sun.net.httpserver.Request$WriteStream.write(Request.java:391) ~[?:1.8.0_191]
        at sun.net.httpserver.FixedLengthOutputStream.write(FixedLengthOutputStream.java:78) ~[?:1.8.0_191]
        at sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:444) ~[?:1.8.0_191]
        at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2315) ~[cache-1.0-SNAPSHOT-jar-with-dependencies.jar:?]
        at org.apache.commons.io.IOUtils.copy(IOUtils.java:2270) ~[cache-1.0-SNAPSHOT-jar-with-dependencies.jar:?]
        at server.TimelineVttHandler.handle(TimelineVttHandler.java:129) [cache-1.0-SNAPSHOT-jar-with-dependencies.jar:?]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) [?:1.8.0_191]
        at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) [?:1.8.0_191]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82) [?:1.8.0_191]
        at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675) [?:1.8.0_191]
        at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) [?:1.8.0_191]
        at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647) [?:1.8.0_191]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]
        Suppressed: java.io.IOException: insufficient bytes written to stream
                at sun.net.httpserver.FixedLengthOutputStream.close(FixedLengthOutputStream.java:89) ~[?:1.8.0_191]
                at sun.net.httpserver.PlaceholderOutputStream.close(ExchangeImpl.java:454) ~[?:1.8.0_191]
                at server.TimelineVttHandler.handle(TimelineVttHandler.java:130) [cache-1.0-SNAPSHOT-jar-with-dependencies.jar:?]
                at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) [?:1.8.0_191]
                at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) [?:1.8.0_191]
                at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82) [?:1.8.0_191]
                at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675) [?:1.8.0_191]
                at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) [?:1.8.0_191]
                at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647) [?:1.8.0_191]
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191]
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191]
                at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]

It is not great problem for client, but resource still alive and we can see it via lsof: 对于客户端来说这不是一个大问题,但是资源仍然有效,我们可以通过lsof看到它:

lsof -n -p 14121  | grep TCPv6
java    13161 cache  143u     sock                0,9      0t0 3617991518 protocol: TCPv6
java    13161 cache  180u     sock                0,9      0t0 3618027565 protocol: TCPv6
java    13161 cache  184u     sock                0,9      0t0 3618017649 protocol: TCPv6

This sockets will never closed while run the application. 运行应用程序时,此套接字永远不会关闭。 How to correct perform it ? 如何正确执行呢?

I solved this problem by throwing IOException from handle method. 我通过从handle方法中抛出IOException解决了这个问题。

                try (final OutputStream os = httpExchange.getResponseBody()) {
                    IOUtils.copy(is, os, 128);
                } catch (IOException e) {
                    logger.warn("Error proxy data", e);
                    throw e;
                }

I have got this thought from contract of method 我从方法合同中得到了这个想法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM