Closed TCP Channel (Netty 3.1.1GA)

Thomas Bocek bocek at ifi.uzh.ch
Sun Aug 23 04:02:33 EDT 2009


Hi Trustin,

I investigated a bit more in this issue and found in
NioClientSocketPipelineSink.java, in line 356 the method
processConnectTimeout() that is called every ~500ms to check if a
connection has timed out. In this method, the selector's key set are
iterated and once a while there is a SelectionKey that is invalid and
the channel is closed:

Line 359, NioClientSocketPipelineSink.java
private void processConnectTimeout(Set<SelectionKey> keys, long
currentTimeNanos) {
  ConnectException cause = null;
  for (SelectionKey k: keys) {
   if (!k.isValid()) {
    close(k);
    continue;
   }
...

However, the selectionKey is invalid because it has been successfully 
finished in connect() in Line 384. So the connection is established and 
the selectionKey is canceld. The SelectionKey remains in the set because 
from the Java API it says: "Keys may be cancelled and
channels may be closed at any time. Hence the presence of a key in one
or more of a selector's key sets does not imply that the key is valid or
that its channel is open." The result is that the connection is closed 
(ClosedChannelException) even though it was successful. I think the 
correct behavior of this method should be:

private void processConnectTimeout(Set<SelectionKey> keys, long
currentTimeNanos) {
  ConnectException cause = null;
   if (k.isValid()) {
    NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment();
    ...

The check for timeout should only be for valid SelectionKeys as invalid 
keys are canceled or closed anyway. Second, the isConnectable is already 
handled by processSelectedKeys(), so I think there is no need for that.

Thomas

Thomas Bocek wrote:
> Hi,
> 
> I'm having the following issue that once a while I get an exception due
> to a ClosedChannelException. I made a test and this happens once per
> every 10'000 connections or so and its very undeterministic. In the test
> I open locally a connection, send data, wait for a reply, and close it.
> Most of the time opening connection works, but in rare occasions it does
> not.
> 
> The exception gets set in:
> 
> NioWorker, 731:
> 
> if (localAddress == null || remoteAddress == null) {
>   if (future != null) {
>     future.setFailure(new ClosedChannelException());
>   }
>   close(channel, succeededFuture(channel));
>   return;
> }
> 
> Here, localAddress is null, and remoteAddress is null. Before the future
> is set, as far as I can see, NioClientSocketPipelineSink in line 146
> calls register(...):
> 
> if (channel.socket.connect(remoteAddress)) {
>   channel.worker.register(channel, future);
> } else {
>   future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
>   channel.connectFuture = future;
>   boss.register(channel);
> }
> 
> The socket in the NioClientSocketChannel class says: bound=false,
> closed=false, connected=false, created=false, and the selector is open
> so I expect that boss.register(...) is called.
> 
> Here is the stacktrace:
> 
> Thread [New I/O client worker #1-2] (Suspended (breakpoint at line 299
> in DefaultChannelFuture))	
> 	DefaultChannelFuture.setFailure(Throwable) line: 299	
> 	NioWorker$RegisterTask.run() line: 731	
> 	NioWorker.processRegisterTaskQueue() line: 260	
> 	NioWorker.run() line: 199	
> 	ThreadRenamingRunnable.run() line: 113	
> 	IoWorkerRunnable.run() line: 53	
> 	ThreadPoolExecutor$Worker.runTask(Runnable) line: 886	
> 	ThreadPoolExecutor$Worker.run() line: 908	
> 	Thread.run() line: 619
> 
> How and when is it safe to assume that a channel is connected and has a
> local and remote address set?
> 
> I'm not sure if there is a mistake in my code (more likely) or in Netty.
> 
> 
> Thomas
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> netty-users mailing list
> netty-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/netty-users



More information about the netty-users mailing list