Клиент Netty генерирует множество состояний сокета TIME_WAIT

Я написал код клиента netty для отправки обработанных данных нескольким клиентам. После работы в течение 3-4 часов я исчерпываю все розетки, и соединения невозможны. Также, когда я проверяю состояния сокетов в ОС, большое количество сокетов находится в состоянии TIME_WAIT.

public class NettyClient {

private static LogHelper logger = new LogHelper(NettyClient.class);

private static EventLoopGroup workerGroup = new NioEventLoopGroup();

private static Bootstrap nettyClient = new Bootstrap()
        .group(workerGroup)
        .channel(NioSocketChannel.class)
        .option(ChannelOption.SO_KEEPALIVE, true)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);

private URL url;
private RequestVo Req;
private ChannelFuture chFuture;
private Object ReportData;
private JAXBContext jbContext;
private static final int CHANNEL_READ_TIMEOUT = 5;


public NettyClient() {
    // TODO Auto-generated constructor stub
}

public NettyClient(RequestVo Req, JAXBContext jbCtx,Object data) {
    this.Req = Req;
    this.ReportData = data;
    this.jbContext = jbCtx;
}

public void sendRequest() {

    logger.debug("In sendRequest()");
    //ChannelFuture chFuture = null;
    try {
        this.url = new URL(Req.getPushAddress());
        //add handlers
        nettyClient.handler(new ChannelInitializer<SocketChannel>() {

            @Override
            public void initChannel(SocketChannel ch) {
                ch.pipeline()
                  .addLast("timeout",
                    new ReadTimeoutHandler(CHANNEL_READ_TIMEOUT, TimeUnit.SECONDS));

                ch.pipeline()
                  .addLast("codec", new HttpClientCodec());

                ch.pipeline()
                  .addLast("inbound",
                     new NettyClientInBoundHandler(Req, jbContext, ReportData));
            }
        });

        //make a connection to the Client
        int port = url.getPort() == -1? url.getDefaultPort():url.getPort();
        chFuture = nettyClient.connect(url.getHost(), port);
        chFuture.addListener(new NettyClientConnectionListener(this.Req.getRequestId()));
    } catch (Exception e) {
        logger.error("Exception: Failed to connect to Client ", e);
    } finally {

    }
}
}

Вот методы из класса ChannelInBoundHandler

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
    Map<String, String> props = new HashMap<String, String>();

    if (msg instanceof HttpResponse) {
        logger.debug("channelRead()");
        HttpResponse httpRes = (HttpResponse) msg;
        HttpResponseStatus httpStatus = httpRes.status();
        props.put(REQUEST_ID, this.Request.getRequestId());
        props.put(CLIENT_RESPONSE_CODE, String.valueOf(httpStatus.code()));
        JmsService.getInstance(DESTINATION).sendTextMessage(props, "");
        logger.debug("channelRead() HttpResponse Code: " + httpStatus.code());
        ctx.close();
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
    Map<String, String> props = new HashMap<String, String>();

    logger.error("exceptionCaught()", cause);
    if (cause instanceof ReadTimeoutException) {
        //If read-timeout, send back the response
        props.put(REQUEST_ID, this.Request.getRequestId());
        props.put(CLIENT_RESPONSE_CODE,
                  String.valueOf(HttpResponseStatus.REQUEST_TIMEOUT.code()));
        JmsService.getInstance(DESTINATION).sendTextMessage(props, "");
        ctx.close();
    }
    else {
        logger.error("Exception: ", cause);
    }
}

Любая идея, что не так в коде, мне очень поможет. Спасибо

вы можете попробовать bootstrap.setOption ("reuseAddress", true);

exudong 17.12.2018 17:16

Также вы уверены, что правильно закрываете все Channel?

Norman Maurer 28.12.2018 21:02

Да, я закрываю канал после исключения тайм-аута чтения или после получения ответа.

Giridhar Kandachar 21.01.2019 10:33

Можно ли повторно использовать открытое соединение вместо того, чтобы каждый раз открывать новое?

Kjartan 24.04.2019 08:50

Вы создаете исходящие соединения быстрее, чем можно освободить их локальные порты. Вам следует попытаться сохранить исходящие соединения, по возможности используя HTTP keepalive.

user207421 24.04.2019 08:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
517
1

Ответы 1

Я не знаком с нетти, но думаю, что смогу объяснить часть вашей проблемы и, надеюсь, помочь вам на этом пути:

Когда вы используете порт, а затем закрываете его, порт не будет автоматически доступен для использования другими процессами сразу. Вместо этого он перейдет в состояние TIME_WAIT на определенный период времени. Для Windows это будет 240 секунд (четыре минуты).

Я предполагаю, что ваш код медленно использует все доступные порты в вашей системе, так как выход портов из состояния TIME_WAIT происходит слишком медленно.

Мне не совсем понятно, откуда берутся фактические номера портов (возможно, они автоматически генерируются url.getDefaultPort()?), Но, возможно, вы сможете найти способ их повторно использовать? Если вы можете сохранить одно или несколько открытых соединений и как-то повторно использовать их, то вы сможете уменьшить частоту запросов на новые порты настолько, чтобы закрытые порты вышли из своего состояния TIME_WAIT.

Порты создаются путем создания новых исходящих подключений. url.getDefaultPort() тут ни при чем.

user207421 24.04.2019 08:54

Другие вопросы по теме