0

I have the following scenario:

  • A server open's a ServerSocketChannel and accept client connections.
  • Every connection (socketA) is handled in a new thread.
  • Inside the thread I open a new SocketChannel (socketB) which connects a another server.
  • The original client connection (socketA) is idle at this time.
  • The new SocketChannel reads data (blocking) from the server.

Now I interrupt the thread. I expected that socketB will be interrupted and closed and socketA will be continue to work. Unfortunately socketA will also be interrupted.

Any idea what could be the problem?

I use the following test methods to reproduce the behavior:

private void testServerSocket() throws IOException, InterruptedException
{
    final InetSocketAddress     address         = new InetSocketAddress( "localhost", 12345 );
    final ServerSocketChannel   serverChannel   = ServerSocketChannel.open();
    serverChannel.socket().bind( address );

    final SocketChannel socketChannel   = serverChannel.accept();

    // start communication in new thread
    final Thread    thread  = new Thread( new Runnable() { @Override public void run() { testWrite( socketChannel ); } } );

    thread.start();

    // wait a little bit
    Thread.sleep( 5000 );

    // interrupt thread, will interrupt the socketChannel.read in testRead()
    thread.interrupt();
    thread.join();

    socketChannel.close();
    serverChannel.close();
}

void testWrite( SocketChannel socketA )
{
    try
    {
        // write to client
        socketA.write( ByteBuffer.wrap( "0123456789".getBytes() ) );

        // open new socket to another server
        testRead();

        // throws ClosedByInterruptException
        socketA.write( ByteBuffer.wrap( "0123456789".getBytes() ) );
    }
    catch( final IOException e )
    {
        e.printStackTrace();
    }
}

void testRead()
{
    try
    {
        final InetSocketAddress address   = new InetSocketAddress( "localhost", 12346 );
        final SocketChannel     socketB   = SocketChannel.open( address );

        // server doesn't send, so this call will block and interrupted 
        socketB.read( ByteBuffer.wrap( new byte[10] ) );

        socketB.close();
    }
    catch( final IOException e )
    {
        e.printStackTrace();
    }
}

1 Answers1

1

You need to clear the thread's interrupted state by calling Thread.interrupted() after the IOException in testRead(). Actually you should catch ClosedByInterruptException and do it there. Otherwise the condition persists and interrupts the write as well.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • But this couldn't be the general solution for the problem. If I replace the SocketChannel code in testRead with a simple Thread.sleep( 20000 ), socketA will not be interrupted. – user1909432 Dec 17 '12 at 17:47
  • And in real life, i have no simple testRead and testWrite functions. For example in my server the testRead function is not from me but a CORBA function from the java runtime. – user1909432 Dec 17 '12 at 17:57
  • @user1909432 The real solution is to not interrupt threads but close the socket and have the thread exit itself on that condition. – user207421 Dec 17 '12 at 20:40
  • How should I do that? The testRead method in the example is in real life a CORBA call that can hang several minutes without timeout. How should I realize a timeout handling without interrupts? As far as I know SocketChannel implements the InterruptibleChannel interface exactly for that reason. – user1909432 Dec 18 '12 at 13:55