Search code examples
javamultithreadingtcpniosocketchannel

Java NIO TCP timeout issue


I am using one SocketChannel in 2 threads, one thread for sending the data and another for receiving the data.

SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(ip,port));
socketChannel.configureBlocking(false);

Thread 1: uses the above socketchannel to write the data

Thread 2: uses the same socketchannel to read the data

I am not using any selectors with the socketchannel as I need the write and read to be asynchronous (using 2 different threads)

PROBLEM: When the connection is lost, the socketchannel.write() and socketchannel.read() operation does not throw any error. It just blocks the operation.

I need to detect the connection loss.

I tried using the heartbeat method in Thread 2 but because the read operation just blocks, this method did not work. Is there any other way to detect the connection loss without using the heartbeat in a new Thread?

Is it possible to throw error while writing/reading if there is connection loss?

Thanks in advance.

EDIT:

Thread 1:

public void run() {
  socketChannel = SendAndReceivePacketUtil.createConnection(ip, port);
  socketChannel.configureBlocking(false);

  RecTask task = new RecTask(socketChannel);
  Thread recThread = new Thread(task);
  recThread.start();

  while(true)
  {
     byte[] data= getDataFromQueue(ip);
     if(data!= null) {
         //print(new String(data));
         sendPacket(data, socketChannel);
     }
   }
}

Thread 2: (RecTask)

public void run() {
  while(true) {
    byte[] data = receivePacket(socketChannel);
    //print(new String(data));
  }
}

Both Thread 1 & 2 have try-catch-finally blocks. finally closes the socketchannel.

sendPacket:

int dataSent = 0;
while (dataSent < data.length) {
    long n = socketChannel.write(buf);
        if (n < 0) {
            throw new Exception();
        }
        dataSent += (int) n;
 }

receivePacket:

int dataRec = 0;
byte[] data = new byte[length];
ByteBuffer buffer = ByteBuffer.wrap(data);

while (dataRec < length) {
    long n = socketChannel.read(buffer);
    if (n < 0) {
        throw new Exception();
    }
    dataRec += (int) n;
}       
return data;

I send and receive data continuously. But as soon as the connection is lost, nothing prints and the code just gets stuck. Its an android wifi direct application. For connection loss scenario I just switch off the wifi module.


Solution

  • I am not using any selectors with the socketchannel as I need the write and read to be asynchronous (using 2 different threads)

    That's not a reason to avoid a Selector. In fact it's rather difficult to write correct non-blocking NIO code without a Selector.

    PROBLEM: When the connection is lost, the socketchannel.write() and socketchannel.read() operation does not throw any error. It just blocks the operation.

    No it doesn't. You're in non-blocking mode. It either returns a postive integer, or zero, or throws an exception. Which is it?

    I tried using the heartbeat method in Thread 2 but because the read operation just blocks, this method did not work.

    The read operation does not block in non-blocking mode.

    Is there any other way to detect the connection loss without using the heartbeat in a new Thread?

    The only reliable way to detect connection loss in TCP is to write to the connection. Eventually this will throw IOException: connection reset. But it won't happen the first time after the connection loss, due to buffering, retries, etc.

    Is it possible to throw error while writing/reading if there is connection loss?

    That's what happens.

    There is something seriously wrong with this question. Either the code you posted isn't the real code or it isn't behaving as you described. You need to post more of it, e.g. your read and write code.