When I run sencha app watch
and then after some time I exit it and start it again, I get a warning that port 1841 is already in use and then it just uses a random port because of that.
Port 1841 already in use. Using dynamic port instead.
No matter how often I kill and restart that command, it refuses to take port 1841... until about 1 minute has passes since I killed it the first time. Then it will happily take port 1841 again (until I exit it the next time...).
The weird thing is that the port is not actually in use. During that one minute time frame I can just start anything else on that port. An http server for instance http-server -p 1841
works just fine. But when I exit the http-server and try another sencha app watch
within the time frame, it claims the port is still in in use...
lsof
doesn't find anything blocking the port either:
# lsof -ti:1841 -sTCP:LISTEN | xargs kill
kill: not enough arguments
Running sencha app watch --port 1841
instead of sencha app watch
made no difference.
So I decompiled sencha.jar using Procyon and found this:
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) {}
}
}
}
Everything else like ServerSocket
, ServerSocketChannel
, InetSocketAddress
and StandardSocketOptions
seems to come from Java standard libraries:
import java.net.StandardSocketOptions;
import java.nio.channels.ServerSocketChannel;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
But it all looks like it should work to me.
Any ideas what is going wrong here?
My SenchaCmd version is 6.5.3.6 btw and I'm on Linux.
Edit:
Is it possible that changing
if (!reuseAddr) {
srv.setOption(StandardSocketOptions.SO_REUSEADDR, false);
}
to
srv.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddr);
would solve the problem?