代码之家  ›  专栏  ›  技术社区  ›  Forivin

为什么SenchaCmd认为端口1841已经在使用,而它没有?

  •  0
  • Forivin  · 技术社区  · 6 年前

    sencha app watch 然后过了一段时间,我退出并再次启动它,我得到一个警告,端口1841已经在使用中,然后它就因为这个原因使用了一个随机端口。

    端口1841已在使用中。改用动态端口。

    无论我多久终止并重新启动一次该命令,它都拒绝接收端口1841。。。直到我第一次杀了它1分钟后。然后它将很高兴地再次使用端口1841(直到我下次退出它…)。

    奇怪的是,这个端口实际上没有被使用。在这一分钟内,我可以在该端口上启动任何其他操作。例如http服务器 http-server -p 1841 sencha应用程序手表 在时间范围内,它声称该端口仍在使用中。。。

    lsof 也没有发现任何东西阻塞端口:

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

    sencha app watch --port 1841 而不是 没什么区别。

    因此,我使用Procyon反编译了sencha.jar并发现:

    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;
    

    但这一切看起来都应该对我有用。
    你知道这里出了什么问题吗?

    编辑 :

    有没有可能

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

    srv.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddr);
    

    这会解决问题吗?

    0 回复  |  直到 6 年前