Skip to content

Close SocketChannel in TcpNioClientConnectionFactory.buildNewConnection() #9694

Closed
@anthologia

Description

@anthologia

Expected Behavior

  • When a connection attempt fails, the SocketChannel should be properly closed, and resources should be released.
  • Socket management should prevent the number of open sockets from increasing indefinitely during retries.

Current Behavior

  • When the target server is down and TcpNioClientConnectionFactory.buildNewConnection() attempts to connect, java.net.ConnectException: Connection refused: no further information is thrown. However, the socket connection is not closed, and the connection retry interval causes the number of sockets to increase indefinitely.
  • When using singleUse=false, clientMode=true, and retryInterval, the number of open sockets increases indefinitely until the target server is up.
// TcpNioClientConnectionFactory class

@Override
protected TcpConnectionSupport buildNewConnection() {
	try {
		SocketChannel socketChannel = SocketChannel.open();
		setSocketAttributes(socketChannel.socket());
		connect(socketChannel);
		TcpNioConnection connection =
				this.tcpNioConnectionSupport.createNewConnection(socketChannel, false, isLookupHost(),
						getApplicationEventPublisher(), getComponentName());
		connection.setUsingDirectBuffers(this.usingDirectBuffers);
		connection.setTaskExecutor(getTaskExecutor());
		Integer sslHandshakeTimeout = getSslHandshakeTimeout();
		if (sslHandshakeTimeout != null && connection instanceof TcpNioSSLConnection) {
			((TcpNioSSLConnection) connection).setHandshakeTimeout(sslHandshakeTimeout);
		}
		TcpConnectionSupport wrappedConnection = wrapConnection(connection);
		if (!wrappedConnection.equals(connection)) {
			connection.setSenders(getSenders());
		}
		initializeConnection(wrappedConnection, socketChannel.socket());
		if (getSoTimeout() > 0) {
			connection.setLastRead(System.currentTimeMillis());
		}
		this.channelMap.put(socketChannel, connection);
		wrappedConnection.publishConnectionOpenEvent();
		this.newChannels.add(socketChannel);
		this.selector.wakeup();
		return wrappedConnection;
	}
	catch (IOException e) {
		throw new UncheckedIOException(e);
	}
	catch (InterruptedException e) {
		Thread.currentThread().interrupt();
		throw new UncheckedIOException(new IOException(e));
	}
}

private void connect(SocketChannel socketChannel) throws IOException, InterruptedException {
	socketChannel.configureBlocking(false);
	socketChannel.connect(new InetSocketAddress(getHost(), getPort()));
	boolean connected = socketChannel.finishConnect();
	long timeLeft = getConnectTimeout().toMillis();
	while (!connected && timeLeft > 0) {
		Thread.sleep(5); // NOSONAR Magic #
		connected = socketChannel.finishConnect();
		timeLeft -= 5; // NOSONAR Magic #
	}
	if (!connected) {
	throw new IOException("Not connected after connectTimeout");
		}
}

Context

  • I believe this may cause resource leakage, as each failed connection attempt opens a new socket that is never closed.
  • I think that when the server is down and the connection fails, the socket should be properly closed, and resources should be released.
  • I'm wondering if adding socketChannel.close() in the event of a connection failure would be a good solution, or if I might be misunderstanding the intended behavior of TcpNioClientConnectionFactory.buildNewConnection().

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions