问题
I'm currently involved in a project at school in which we are building a communication system to be used on Android phones. For this, we will be using a server which opens sockets towards all clients, making them communicate.
I've done several chat applications before without any problems with sockets or thread handling but this time, for some reason, it boogles my mind.
The problem is that the application starts to listen as soon as I initiate the ServerSocket
object, serverSocket = new ServerSocket(5000)
, and not at the serverSocket.accept()
.
Why is that?
As soon as I use the following method:
public void startListen(String port) {
try {
serverSocket = new ServerSocket(Integer.parseInt(port));
portField.setEditable(false);
} catch (IOException e) {
printMessage("Failed to initiate serverSocket: " + e.toString());
}}
The port is showing up as Listening in the command prompt (using netstat
). If I don't call it, the port is not listed as listening.
TCP 0.0.0.0:5000 Computer:0 LISTENING
So, is here anything I'm missing when using the ServerSocket
object? My older programs using ServerSocket
doesnt start listening until I call accept()
.
回答1:
If you're talking about the Java ServerSocket, there's no listen
method for it, presumably since it's distinct from a client-side socket. In that case, once it has a port number (either in the constructor or as part of a bind
), it can just go ahead and listen automagically.
The reason "regular" sockets (a la BSD) have a listen is because the same type is used for client and server, so you need to decide yourself how you're going to use it. That's not the case with ServerSocket
since, well, it's a server socket :-)
To be honest, I'm not sure why you'd care whether or not the listening is active before accept
is called. It's the "listen" call (which is implicit in this class) that should mark your server open for business. At that point, the communication layers should start allowing incoming calls to be queued up waiting for you to call accept
. That's generally the way they work, queuing the requests in case your program is a little slow in accepting them.
In terms as to why it does it, it's actually supposed to according to the source code. In the OpenJDK6 source/share/classes/java/net/ServerSocket.java
, the constructors all end up calling a single constructor:
public ServerSocket(int port, int backlog, InetAddress bindAddr)
throws IOException {
setImpl();
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException(
"Port value out of range: " + port);
if (backlog < 1)
backlog = 50;
try {
bind(new InetSocketAddress(bindAddr, port), backlog);
} catch(SecurityException e) {
close();
throw e;
} catch(IOException e) {
close();
throw e;
}
}
And that call to bind
(same file) follows:
public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
throw new SocketException("Already bound");
if (endpoint == null)
endpoint = new InetSocketAddress(0);
if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type");
InetSocketAddress epoint = (InetSocketAddress) endpoint;
if (epoint.isUnresolved())
throw new SocketException("Unresolved address");
if (backlog < 1)
backlog = 50;
try {
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkListen(epoint.getPort());
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
bound = true;
} catch(SecurityException e) {
bound = false;
throw e;
} catch(IOException e) {
bound = false;
throw e;
}
}
The relevant bit there is:
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
meaning that both the bind
and listen
are done at the lower level when you create the socket.
So the question is not so much "why is it suddenly appearing in netstat
?" but "why wasn't it appearing in netstat
before?"
I'd probably put that down to a mis-read on your part, or a not-so-good implementation of netstat
. The former is more likely unless you were specifically testing for a socket you hadn't called accept
on, which would be unlikely.
回答2:
I think you have a slightly wrong idea of the purpose of accept
. Liken a ServerSocket to a queue and accept
to a blocking dequeue operation. The socket enqueues incoming connections as soon as it is bound to a port and the accept
method dequeues them at its own pace. So yes, they could have named accept
better, something less confusing.
来源:https://stackoverflow.com/questions/13098771/serversocket-listens-without-accept