繁体   English   中英

Java NIO:serverSocketChannel接受套接字请求,客户端收到接受,但服务器未记录

[英]Java NIO: A serverSocketChannel accepts a socket request and client receives the acceptance but the server does not log it

我正在尝试基于无阻塞NIO消息开发自己的通信库。 我已经阅读了1000篇关于它的教程和书籍,我认为最后我可以使用很少的并发连接。 但是当服务器端同时存在许多连接时,我遇到了一些问题。

我有4种私有方法的典型选择器实现:accept,finishConnect,读写。 我的问题在于前两个:Accept和finishConnect。

当客户端打开新的套接字,并且可接受的键唤醒选择器时,将执行以下代码。

private void accept(SelectionKey key) {
    try {
        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
        SocketChannel sc = ssc.accept();
        sc.configureBlocking(false);
        LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connexion completed");
        changeInterest(sc, SelectionKey.OP_READ);
        eventManager.addEvent(new ConnectionEstablished(sc));
    } catch (Throwable e) {
        NIOException ne = new NIOException(NIOException.ErrorType.ACCEPTING_CONNECTION, e);
        eventManager.addEvent(new ErrorEvent(null, ne));
    }
}

在客户端,我具有connect方法的这种实现,一旦服务器处理了其可接受的套接字密钥,就会调用该方法。

private void finishConnect(SelectionKey key) {
    SocketChannel sc = (SocketChannel) key.channel();
    try {
        if (sc.finishConnect()) {
            eventManager.addEvent(new ConnectionEstablished(sc));
            LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connection finished");
        } else {
            LOGGER.debug("REFUSED " + sc + " - " + sc.socket().toString());
            refusedConnection(sc, null);
            key.cancel();
        }
    } catch (Exception e) {
        refusedConnection(sc, e);
        key.cancel();
    }
}

事实是,当我创建一些连接被接受时,客户端将执行finishConnect消息(并且我可以看到使用所使用的端口建立的套接字连接)。 但是我在服务器端找不到这种连接接受,没有使用这些端口的连接完成日志消息!

我怀疑ssc.accept()和日志调用之间可能会出现异常,因此我添加了一些额外的日志消息,以检查哪个指令正在炸毁所有内容。 对于进入accept方法的所有键,序列均已完成。

如果我什至在日志中看不到任何错误消息怎么办?

编辑:我对一次打开的套接字数进行了一些测试。 当客户端开始运行时,服务器上只有一个openSocket:服务器套接字。 之后,它最多具有200个同时打开的套接字,并且在客户端执行结束时,服务器将返回到1个打开的套接字。 我猜他们从来没有被算过

到目前为止,我已经采取了一种变通方法,该方法可以监视节点上共存连接的数量,并延迟接受新的连接,直到该数量减少到给定的阈值为止。 但是,我想了解发生了什么问题。

谢谢你的帮助。

由于存在积压队列,因此完全可以在执行accept()之前完成大量客户端连接。 因此,这里没有实际要解决的问题。

但是,您是否曾经执行过accept()方法? 这是您需要调查的错误。

正如EJP所建议的那样,问题在于待办事项队列。 我正在使用bind(SocketAddress local)方法绑定ServerSocketChannel。

当套接字请求到达JVM时,它将排队进入待办事项队列,并在那里等待,直到侦听器触发要接受的相应密钥的过程为止。 实际的问题在于此队列的大小,使用bind方法,它最多可以存储50个连接。

当连接请求达到高峰时,队列上就会发生溢出,其中一些会丢失。 为避免发生这种情况,方法bind(SocketAddress local,int backlog)允许更改队列的容量并增加队列的容量。

另一方面,在非阻塞模式下工作时,客户端节点上的选择器不需要接受连接即可处理OP_CONNECT密钥。 SYN-ACK TCP消息的接收将触发选择器中的相应密钥。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM