ServerSocket侦听没有accept()

时间:2012-10-27 09:13:56

标签: java serversocket

我目前正在学校参与一个项目,我们正在建立一个用于Android手机的通信系统。为此,我们将使用一个服务器向所有客户端打开套接字,使它们进行通信。

我之前已经完成了几个聊天应用程序,没有任何套接字或线程处理问题,但这一次,由于某些原因,它让我感到困惑。

问题是,一旦我发起ServerSocket对象serverSocket = new ServerSocket(5000),而不是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());
}}

端口在命令提示符下显示为Listening(使用netstat)。如果我不调用它,则端口不会被列为监听。

  

TCP 0.0.0.0:5000计算机:0聆听

那么,使用ServerSocket对象时,我在这里找不到任何东西吗?在我致电ServerSocket之前,我使用accept()的旧程序才开始收听。

3 个答案:

答案 0 :(得分:7)

如果您正在谈论Java ServerSocket,那么它没有listen方法,大概是因为它与客户端套接字不同。在这种情况下,一旦它有一个端口号(在构造函数中或作为bind的一部分),它就可以继续自动监听。

“常规”套接字(la BSD)有一个监听的原因是因为客户端服务器使用了相同的类型,所以你需要自己决定如何使用它。 ServerSocket的情况并非如此,因为它是服务器套接字: - )

说实话,我不确定为什么在调用accept之前你是否关心是否有效。这是“监听”调用(这个类中隐含的),应该标记您的服务器为业务开放。此时,通信层应该开始允许传入呼叫排队等待您呼叫accept。这通常是他们工作的方式,排队请求以防你的程序接受它们的速度有点慢。


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

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(同一文件)的调用如下:

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都在较低级别完成。

所以问题不在于“为什么它突然出现在netstat?”但“为什么它不出现在netstat之前?”

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

答案 1 :(得分:2)

我认为你对accept的目的略有错误。将ServerSocket分配到队列,将accept分配给阻止出列操作。套接字一旦绑定到端口就会将传入连接排入队列,accept方法会按照自己的节奏将它们出列。所以,是的,他们可以更好地命名accept,更不用说混淆了。

答案 2 :(得分:0)

一个关键原因可能是myServerSocket.setSoTimeout()accept()调用会阻塞-除非您在调用之前定义了超时,否则它只会在该持续时间内阻塞,然后无害地(即ServerSocket仍然有效)抛出SocketTimeoutException

这样,线程就在您的控制之下……但是当您不在暂时阻止accept()的调用中,在那毫秒内发生了什么?客户是否会找到监听端口? -这就是为什么端口监听时不需要accept()调用是一件好事的原因。

问题在于,应用程序一开始就开始监听 初始化ServerSocket对象serverSocket = new ServerSocket(5000),而不是初始化serverSocket.accept()

我很感谢这个问题(-> upvote),因为这正是我想知道的这种行为,而无需进行实验。 Google的术语是“ java serversocket如果尝试在不接受的情况下进行连接会发生什么情况”,那么这个问题就出现在第一个匹配项的链接列表中。