ServerSocket 在没有 accept() 的情况下监听 [英] ServerSocket listens without accept()

查看:68
本文介绍了ServerSocket 在没有 accept() 的情况下监听的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前在学校参与一个项目,我们正在构建一个可在 Android 手机上使用的通信系统.为此,我们将使用一个服务器向所有客户端打开套接字,使它们能够通信.

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.

问题是应用程序在我启动 ServerSocket 对象后立即开始侦听,serverSocket = new ServerSocket(5000),而不是在 serverSocket.accept().

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().

这是为什么?

只要我使用以下方法:

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());
}}

端口在命令提示符中显示为正在侦听(使用 netstat).如果我不调用它,该端口不会被列为侦听.

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 计算机:0 正在侦听

TCP 0.0.0.0:5000 Computer:0 LISTENING

那么,在使用 ServerSocket 对象时,我遗漏了什么吗?我使用 ServerSocket 的旧程序在我调用 accept() 之前不会开始监听.

So, is here anything I'm missing when using the ServerSocket object? My older programs using ServerSocket doesnt start listening until I call accept().

推荐答案

如果您在谈论 Java ServerSocket,则没有针对它的 listen 方法,大概是因为它与客户端不同插座.在这种情况下,一旦它有了端口号(在构造函数中或作为 bind 的一部分),它就可以继续自动侦听.

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.

常规"套接字(a la BSD)具有监听的原因是因为客户端使用相同的类型,因此您需要自己决定如何使用它.ServerSocket 不是这种情况,因为它是一个 server 套接字 :-)

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 :-)

老实说,我不知道为什么在调用 accept 之前你会关心监听是否处于活动状态.监听"调用(在这个类中是隐含的)应该标记您的服务器开始营业.那时,通信层应该开始允许传入呼叫排队等待您调用accept.这通常是他们的工作方式,对请求进行排队,以防您的程序在接受请求时有点慢.

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.

至于为什么要这样做,实际上应该根据源代码.在 OpenJDK6 source/share/classes/java/net/ServerSocket.java 中,构造函数最终都调用了一个构造函数:

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;
    }
}

bind(同一个文件)的调用如下:

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;
    }
}

相关位是:

getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);

意味着 bind listen 都是在创建套接字时在较低级别完成的.

meaning that both the bind and listen are done at the lower level when you create the socket.

所以问题不在于为什么它会突然出现在 netstat 中?"但是为什么它之前没有出现在 netstat 中?"

So the question is not so much "why is it suddenly appearing in netstat?" but "why wasn't it appearing in netstat before?"

我可能会将其归结为您误读了,或者 netstat 的实现不太好.前者更有可能,除非您专门测试未调用 accept 的套接字,这不太可能.

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.

这篇关于ServerSocket 在没有 accept() 的情况下监听的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆