0

I'm just wondering if it is possible to use the SocketChannel class (with ByteBuffer) to simulate the blocking features of the regular Socket class in Java. I made two Test projects, one simulating the Client and the other simulating the Server:

Client Code:

    public static void main(String[] args) throws IOException {

    SocketChannel socket = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6789));

    //Simulate this:
    //DataOutputStream dos = new DataOutputStream(socket.socket().getOutputStream());
    //dos.writeInt(4);
    //dos.writeInt(6);

    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.putInt(4);
    buffer.flip();
    socket.write(buffer);
    buffer.clear();
    buffer.putInt(6);
    buffer.flip();
    socket.write(buffer);
}

Server Code:

    public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.socket().bind(new InetSocketAddress(6789));
    SocketChannel socketCh = ssc.accept();
    socketCh.configureBlocking(true);
    // Simulate this
    // DataInputStream dis = new DataInputStream(socketCh.socket().getInputStream());
    // System.out.println(dis.readInt());
    // System.out.println(dis.readInt());

    // This is something to avoid. This is not the same as what is up above
    // If the 2nd line prints -1, the 3rd prints 4
    // If the 2nd line prints 4, the 3rd prints 6
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    socketCh.read(buffer);
    buffer.rewind();
    System.out.println("First number: " + buffer.getInt());
    buffer.clear();
    System.out.println("Change: " + socketCh.read(buffer));
    buffer.rewind();
    System.out.println("Second Number: " + buffer.getInt());
}

As I said in the comments, the results of running the Server then the Client (in that order) are unpredictable, since sometimes the second number might remain as 4 or become 6, with the Change being -1 or 4(bytes in Integer) respectively.

As for the server side, I know I can make it wait so that the second socketCh.read(buffer) returns a value other than -1, which means nothing was written (I presume) in the SocketChannel.

However, on the client side, I don't have any ideas.

I am aware that I can instead use DataOutputStream and DataInputStream and do it the old fashioned way, but I want to know how to do it with SocketChannels simply for convenience. Also you can't go wrong with another trick up your sleeve.

Even though I manually configured the server as blocking, I assume it's the default configuration so it's ok to discard it.

Thank you in advance! PS: Hopefully I could avoid using the Selector classes for such a simple task...

EDIT: I know that the Selector classes can only be used for non-blocking mode.

1 Answers1

1

You're throwing away extra data that may have been read, and assuming that each read delivers exactly what corresponds to each write (for example that the first one delivers only the int). There is nothing in TCP that guarantees that.

Change the rewind() to flip(); change the clear() to compact(); add some checking of the return value of read(); and it should work as expected.

You can't use Selector in blocking mode.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Alright thanks! Yeah I am aware that you can't use Selector in blocking mode, however I wished to avoid having to configure the SocketChannel to non-blocking and having to do all that for just this simple task. – Noel Saldanha May 10 '16 at 05:48
  • Makes a whole ton more sense now that I read what compact() does in detail. That's what I get for skimming over a book I guess :\. Thanks man, really appreciate it – Noel Saldanha May 10 '16 at 06:20