ServerSocket listens without accept()

Deadly 提交于 2019-12-12 09:07:16

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!