0

Respect,

I try to use new Java NIO2 to create Asynchronous SocketChannel on the client and on the server side and communicate, but problem is that all messages I sent to socket on the server, socket read all as one message. here is code:

I create handlers for writing and reading data:

ReadHandler:

public class ReadHandler implements CompletionHandler<Integer, Msg> {


private AsynchronousSocketChannel _socket;
private SocketHandler _socketHandler;

private ByteBuffer _buffer;

public ReadHandler(SocketHandler socketHandler) {

    this._socketHandler = socketHandler;
    _buffer = ByteBuffer.allocate(100);

    this._socket = this._socketHandler.getSocket();
    this._socket.read(_buffer, null, this);
}

@Override
public void completed(Integer result, Msg attachment) {

    System.out.println("readdddd " + result);

    String message = new String(_buffer.array());
    System.out.println("mess:" + message);

}

@Override
public void failed(Throwable exc, Msg attachment) {
    System.out.println(exc.getMessage());
}

}

ClientWriteHandler

public class ClientWriteHandler implements CompletionHandler<Integer, Msg> {

private AsynchronousSocketChannel _socket;
private ClientSocket _clientHandler;

private ByteBuffer _buffer;

public ClientWriteHandler(ClientSocket clientHandler) {


    this._clientHandler = clientHandler;
    _buffer = ByteBuffer.allocate(2048);
    this._socket = this._clientHandler.getSocket();
}

@Override
public void completed(Integer result, Msg attachment) {

    System.out.println("write " + result);
    _buffer.clear();
}

@Override
public void failed(Throwable exc, Msg attachment) {
    System.out.println(exc.getMessage());
}

public void write(String data) {
    _buffer = ByteBuffer.allocate(2048);
    this._socket.write(_buffer.wrap(data.getBytes()), new Msg(), this);

}

}

Then I call write method 2 time

socket = AsynchronousSocketChannel.open();
        socket.connect(new InetSocketAddress("localhost", port)).get();
        writeHandler = new ClientWriteHandler(this);
        writeHandler.write("hellooo server :)");
        writeHandler.write("hellooo server again :)");

I try to use clear() function on the ByteBuffer but no effect. Any suggestion?

user2803095
  • 347
  • 1
  • 4
  • 16

3 Answers3

2

WritePendingException was thrown not because the buffer is full. It is thrown because writing is not completed but another starts to write.

tien113
  • 33
  • 9
0

You send a few bytes in the first .write() call and send a few more bytes in the second call to .write(). And the server receives them all. TCP is byte oriented. If you want anything like a message, you have to seperate the messages you send on your own, e.g. by special line break characters or XML tags.

Jonas
  • 121,568
  • 97
  • 310
  • 388
  • Oke but what to do if my ByteBuffer is full, I try to clear bytebuffer but then I got error message Exception in thread "main" java.nio.channels.WritePendingException – user2803095 Apr 24 '14 at 13:50
0

I work on this and I found solution and its work as I imagined.

Inside of ClientWrite handler I added datas list and set write method inside try..catch to check if write() is finihed, if writing is still in process I add new string to datas list. When write method is finished I check datas list for new messages and write message again.

public class ClientWriteHandler implements CompletionHandler<Integer, ByteBuffer> {

private AsynchronousSocketChannel _socket;
private ClientSocket _clientHandler;

private ByteBuffer _buffer;
private List<String> datas;

private boolean finished;

public ClientWriteHandler(ClientSocket clientHandler) {


    this._clientHandler = clientHandler;
    _buffer = ByteBuffer.allocate(2048);
    this._socket = this._clientHandler.getSocket();
    finished = true;
    datas = new ArrayList<>();
}

@Override
public void completed(Integer result, ByteBuffer attachment) {

    System.out.println("client write complete " + result);

    if(datas.size() > 0) {
        this._socket.write(_buffer.wrap(datas.remove(0).getBytes()), _buffer, this);
    }
    else {
        /////
    }
}

@Override
public void failed(Throwable exc, ByteBuffer attachment) {
    System.out.println(exc.getMessage());
}

public void write(String data) {

    try {
        //finished = false;
        this._socket.write(_buffer.wrap(data.getBytes()), _buffer, this);
    }catch(WritePendingException ex) {

        datas.add(data);
    }
}

}

Also I send buffer in attachment. Inside ReadHandler when reading is complete I clear ByteBuffer and call read() method again, so next reading I got as new line, now I dont need to set line separator.

public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {


private AsynchronousSocketChannel _socket;
private SocketHandler _socketHandler;

private ByteBuffer _buffer;

public ReadHandler(SocketHandler socketHandler) {

    this._socketHandler = socketHandler;
    _buffer = ByteBuffer.allocate(2048);

    this._socket = this._socketHandler.getSocket();
    this._socket.read(_buffer, _buffer, this);
}

@Override
public void completed(Integer result, ByteBuffer attachment) {

    attachment.flip();
    System.out.println("readdddd " + result);

    String message = new String(attachment.array());
    System.out.println("mess:" + message);

    _buffer.clear();
    this._socket.read(_buffer, _buffer, this);

}

@Override
public void failed(Throwable exc, ByteBuffer attachment) {
    System.out.println(exc.getMessage());
}

}

For now this works so good, but i will check how this code will behave when I went on with more complex stuffs. What do you think for this solution is it ok?

user2803095
  • 347
  • 1
  • 4
  • 16