0

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.

armor--
  • 45
  • 8

2 Answers2

1

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I have updated the question with the required code. Although I am in the non-blocking mode, I still cannot print anything when the connection is lost. Also the code does not enter the catch/finally block and that is why I am assuming that the code waits for the read/write operation. – armor-- May 01 '15 at 06:51
  • @Pulkit Obviously both your reads and your writes are returning zero, which causes infinite loops. This is why you need `select().` Writing non-blocking loops without a `select()` is just poor technique and a waste of the CPU's time. – user207421 May 01 '15 at 06:52
  • Is it possible to make read and write asynchronous using select? Also, if I change socketChannel.configureBloacking() to true, then the problem should be solved, right? – armor-- May 01 '15 at 06:58
  • Correct. I would use blocking mode in this case, as obviously the threads don't have anything else to do except read or write, otherwise you wouldn't be writing these loops. – user207421 May 01 '15 at 07:04
  • But in case of blocking mode, write and read would also be dependent on each other. As in if data is being written to socketchannel, at the same time I cannot read the data from the socketchannel. Isn't it? – armor-- May 01 '15 at 07:09
  • Is it a good idea to use NIO for asynchronous file transfer as compared to old-fashioned IO? Can you please guide me on how to use select() in this scenario. Thanks :) – armor-- May 01 '15 at 07:12
  • @Pulkit No. You can read and write at the same time in blocking mode as well as in non-blocking mode. I don't really see why you should use NIIO at all here, let alone non-blocking mode. I would get it working with `java.net.Socket` first and then see if you have a problem. – user207421 May 01 '15 at 08:47
0

You can look for enabling TCP-KEEP alive option on the socket. On idle connection keep-alive messages are sent and ACK is expected for those at the TCP layer.

If TCP-KEEP alive fails, your next read/write operation will result in error (ECONNRESET) which can be used as a sign of connection loss.

Prabhu
  • 3,443
  • 15
  • 26
  • Can we not set socket options with lesser time out values for keep alives? – Prabhu May 01 '15 at 06:20
  • As far as I know it is dependent on the OS. You will have to change it at the OS level – armor-- May 01 '15 at 06:48
  • @Prahbu On some platforms, yes, but not via Java code. On other platforms you have to set it at the operating system configuration level, which requires administrative privilege. – user207421 May 01 '15 at 06:52
  • @EJP. Ah! I see. Wasn't aware of Java limitation. Thanks. – Prabhu May 01 '15 at 06:57