0

I am trying to setup an AsynchronousServerSocketChannel that accepts connections from clients and send and receive messages as needed (not necessarily request->response). To facilitate this, I am using asynchronous read and write calls with separate completion handlers. The issue I am having now is that when a client disconnects, the result that is passed to my completion handler isn't -1 and the tread continues to attempt to read. I would like my servers connections to be closed automatically when the corresponding client connection closes.

Here is the code for my read completion handler:

    class ReadHandler implements CompletionHandler<Integer, Attachment> {

        @Override
        public void completed(Integer result, Attachment att) {

            if (result < 0) {
                try {
                    System.out.println("Peer at " + att.clientAddr + " has disconnected.");
                    att.channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                att.readBuffer.flip();
                int limits = att.readBuffer.limit();
                byte bytes[] = new byte[limits];
                att.readBuffer.get(bytes, 0, limits);
                att.readBuffer.clear();

                if(att.hsDone) {
                    // process incoming msg
                    peer.processMessage(att.connectedPeerId, bytes);

                } else { // if handshake has not been done
                    att.connectedPeerId = peer.processHandshake(bytes);
                    System.out.println("Shook hands with peer " + att.connectedPeerId + ".");
                    if(att.connectedPeerId < 0) {
                        try {
                            att.channel.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        att.hsDone = true;
                        att.writeBuffer.put(message.handshakeMsg(peer.id));
                        att.writeBuffer.flip();
                        WriteHandler handler = new WriteHandler();
                        att.channel.write(att.writeBuffer, att, handler);
                    }
                }
                att.readBuffer.flip();
                att.channel.read(att.readBuffer, att, this);
            }
        }

        @Override
        public void failed(Throwable exc, Attachment att) {
            System.err.println(exc.getMessage());
        }
    }

And for my write completion handler:

    class WriteHandler implements CompletionHandler<Integer, Attachment> {

        @Override
        public void completed(Integer result, Attachment att) {
                att.writeBuffer.clear();

                // check if msg needs to be sent
                byte data[] = peer.getNextMsg(att.connectedPeerId);

                att.writeBuffer.put(data);
                att.writeBuffer.flip();
                if(att.channel.isOpen())
                    att.channel.write(att.writeBuffer, att, this);
        }

        @Override
        public void failed(Throwable exc, Attachment att) {
            System.err.println(exc.getMessage());
        }
    }

Any help solving this issue is appreciated.

  • What *is* the result passed to your completion handler? – user207421 Apr 01 '21 at 00:42
  • @user207421 The result is 0 each read. – Adam Tamargo Apr 01 '21 at 19:13
  • 1
    That means that the read buffer was already full. You should *not* `flip()` before `read()` (or `put()`). Only before `write()` or `get()`. Also, you should call `compact()` after the `get()` and the `write()`, not `clear()`. You should also get `limit()-position()` bytes out of it, not `limit()`. – user207421 Apr 02 '21 at 01:14
  • Thank you. Sorry my understanding of how the buffers and nio channels work is still limited. This solved the problem (removing the flip()) – Adam Tamargo Apr 08 '21 at 18:04

0 Answers0