Почему SenchaCmd считает, что порт 1841 уже используется, а его нет? - PullRequest
0 голосов
/ 27 марта 2019

Когда я запускаю sencha app watch, а затем через некоторое время я выхожу из него и запускаю его снова, я получаю предупреждение о том, что порт 1841 уже используется, а затем он просто использует случайный порт из-за этого.

Порт 1841 уже используется. Вместо этого используется динамический порт.

Независимо от того, как часто я убиваю и перезапускаю эту команду, она отказывается принимать порт 1841 ... пока не пройдет около 1 минуты с тех пор, как я убил его в первый раз. Тогда он снова с радостью примет порт 1841 (пока я не выйду из него в следующий раз ...).

Странно то, что порт на самом деле не используется. За этот минутный промежуток времени я могу просто запустить что-нибудь еще на этом порту. Например, http-сервер http-server -p 1841 работает просто отлично. Но когда я выхожу из http-сервера и пробую другой sencha app watch в течение определенного периода времени, он утверждает, что порт все еще используется ...

lsof также не находит ничего, что блокирует порт:

# lsof -ti:1841 -sTCP:LISTEN | xargs kill
kill: not enough arguments

Запуск sencha app watch --port 1841 вместо sencha app watch без разницы.

Итак, я декомпилировал sencha.jar, используя Procyon, и нашел это:

if (this._port > 0 && !NetworkUtil.isPortAvailable(this._port)) {
    WebServerTask._logger.warn("Port {} already in use.  Using dynamic port instead.", (Object)this._port);
    this._port = 0;
}

isPortAvailable

public static synchronized boolean isPortAvailable(final int port) {
    return _isPortAvailable(port, "127.0.0.1");
}

_isPortAvailable:

private static boolean _isPortAvailable(final int port, final String address) {
    return _socketChannelPortAvailable(port, address) && _serverSocketPortAvailable(port, address);
}

_serverSocketPortAvailable

private static boolean _serverSocketPortAvailable(final int p, final String address) {
    ServerSocket srv = null;
    try {
        srv = new ServerSocket();
        srv.setReuseAddress(false);
        if (!StringUtil.isNullOrEmpty(address)) {
            srv.bind(new InetSocketAddress(address, p));
        }
        else {
            srv.bind(new InetSocketAddress(p));
        }
        return true;
    }
    catch (Exception ex2) {
        return false;
    }
    finally {
        if (srv != null) {
            try {
                srv.close();
            }
            catch (Exception ex) {
                throw BasicException.raise(ex);
            }
        }
    }
}

_socketChannelPortAvailable with 2 parameters

private static boolean _socketChannelPortAvailable(final int p, final String address) {
    return _socketChannelPortAvailable(p, address, true);
}

_socketChannelPortAvailable with 3 parameters

private static boolean _socketChannelPortAvailable(final int p, final String address, final boolean reuseAddr) {
    ServerSocketChannel srv = null;
    try {
        srv = ServerSocketChannel.open();
        if (!reuseAddr) {
            srv.setOption(StandardSocketOptions.SO_REUSEADDR, false);
        }
        if (!StringUtil.isNullOrEmpty(address)) {
            srv.bind(new InetSocketAddress(address, p));
        }
        else {
            srv.bind(new InetSocketAddress(p));
        }
        return true;
    }
    catch (Exception ex) {
        return false;
    }
    finally {
        if (srv != null) {
            try {
                srv.close();
            }
            catch (Exception ex2) {}
        }
    }
}

Все остальное, например ServerSocket, ServerSocketChannel, InetSocketAddress и StandardSocketOptions, похоже, происходит из стандартных библиотек Java:

import java.net.StandardSocketOptions;
import java.nio.channels.ServerSocketChannel;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;

Но все это выглядит так, как будто это должно работать для меня.
Есть идеи, что здесь происходит не так?

Моя версия SenchaCmd - 6.5.3.6 и я в Linux.

Редактировать

Возможно ли, что изменение

if (!reuseAddr) {
    srv.setOption(StandardSocketOptions.SO_REUSEADDR, false);
}

до

srv.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddr);

решит проблему?

...