Java HttpServer: утечка сокетов - PullRequest
       17

Java HttpServer: утечка сокетов

0 голосов
/ 02 декабря 2018

У меня есть следующий обработчик прокси (используется встроенный клиент 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);
                }
            }
    ....
}

иногда происходит следующее

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]

Это не большая проблема для клиента, но ресурс по-прежнемуживой, и мы можем видеть это через 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

Эти сокеты никогда не будут закрываться при запуске приложения.Как правильно это выполнить?

1 Ответ

0 голосов
/ 03 декабря 2018

Я решил эту проблему, бросив IOException из handle метода.

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

Я получил эту мысль из контракта метода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...