TcpNioConnection close throws Exception (java.nio.channels.ClosedChannelException)

37 Views Asked by At

scenario is we need to configure the maxClient and if it is reached we have to close the connection if it is greater than maxClient. For this we are adding connectionId in List and if list is greater than max client then we close the TcpNioConnection. but while we close it throws below Exception.

java.nio.channels.ClosedChannelException: null at java.base/java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:222) at org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory.createConnectionForAcceptedChannel(TcpNioServerConnectionFactory.java:260) at org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory.doAccept(TcpNioServerConnectionFactory.java:229) at org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory.keyAcceptable(AbstractConnectionFactory.java:776) at org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory.handleKey(AbstractConnectionFactory.java:725) at org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory.processNioSelections(AbstractConnectionFactory.java:672) at org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory.doSelect(TcpNioServerConnectionFactory.java:194) at org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory.run(TcpNioServerConnectionFactory.java:155) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)

Below is the code

private final Logger log = LoggerFactory.getLogger(TcpConnectionApplicationListener.class);
   
List<String> connectionIdList = new ArrayList<String>();

@Override
public void onApplicationEvent(TcpConnectionEvent event) {
    String connectionId = event.getConnectionId();
    String ipAddressPort = null;
    if(Objects.nonNull(connectionId)) {
        ipAddressPort = connectionId.substring(0,connectionId.lastIndexOf(":"));
        ipAddressPort = ipAddressPort.substring(0, ipAddressPort.lastIndexOf(":"));
    }
    log.info("ipAddressPort >>> "+ipAddressPort);
        
    if (event.getSource() instanceof TcpNioConnection) {
        log.info("inside connection factory >>> ");
        TcpNioConnection nioConnection = (TcpNioConnection) event.getSource();
        if(connectionIdList.size() > 1) {
                nioConnection.close();
                log.info("isClosed >>> "+ nioConnection.getSocketInfo().isClosed());
            return;
        }
    }
        
        
    if (event instanceof TcpConnectionOpenEvent) {
            
        connectionIdList.add(event.getConnectionId());
        log.info("TcpConnectionOpenEvent connection id = {}",connectionIdList.size());
            
        log.info("TCP Open connection event with id={}", event.getConnectionId());
               
    } else if (event instanceof TcpConnectionCloseEvent) {
            
        connectionIdList.remove(event.getConnectionId());
        log.info("TcpConnectionCloseEvent connection id = {}",connectionIdList.size());
            
        log.info("TCP Close connection event with id={}", event.getConnectionId());
           
    }   
}

Below is the code for Integration Flow

IntegrationFlows.from(Tcp.inboundGateway(Tcp.nioServer(port)
         .soReceiveBufferSize(512)
         .deserializer(new MessageDeserializer())
         .serializer(new MessageSerializer())
         )) 
            .log()
            .transform(Transformers.objectToString())
            .handle("outboundService", "processAndSendMessage")
            .get();
}

can you please let me know how to resolve this issue or is there any other way that we can configure max clients in Tcp.nioServer so that many connections only Exists.

1

There are 1 best solutions below

0
Artem Bilan On

Instead of closing connection I suggest to thrown an exception. This way the logic in the TcpNioServerConnectionFactory will be like this:

private TcpNioConnection createTcpNioConnection(SocketChannel socketChannel) {
    try {
        TcpNioConnection connection = this.tcpNioConnectionSupport.createNewConnection(socketChannel, true,
                isLookupHost(), getApplicationEventPublisher(), getComponentName());
        connection.setUsingDirectBuffers(this.usingDirectBuffers);
        TcpConnectionSupport wrappedConnection = wrapConnection(connection);
        if (!wrappedConnection.equals(connection)) {
            connection.setSenders(getSenders());
        }
        initializeConnection(wrappedConnection, socketChannel.socket());
        wrappedConnection.publishConnectionOpenEvent();
        return connection;
    }
    catch (Exception ex) {
        logger.error(ex, "Failed to establish new incoming connection");
        return null;
    }
}

You also can do that from a custom TcpNioConnectionSupport instead of an event listener.