Synchronous IO with nio
Hello,
I have been programming in Java for a while but today is my first shot at NIO.
I'm implementing a custom protocol over TCP between a java server and several Java and C clients. The classical one-thread-per-client approach works with a couple of test connections, but I'm afraid it will not scale:
- I will not have control on all clients programs
- I don't know yet the expected traffic
- I might introduce bugs as well in the sever program and leak sockets and threads
Here is the code for the classical approach:
ServerSocket server.accept() = ...;
Socket client = server.accept();
Thread clientThread =new ClientThread(client);
clientThread.start();
Where ClientThread's run method deos the following:
BufferedReader reader =new BufferedReader(new InputStreamReader(client.getInputStream()));
while (isConnected){
String pdu = reader.readLine();
storeClientInfo(pdu);
}
The key is that in order to make for a very simple protocol we designed it so that each PDU is one line of text, sent over TCP. Reading one PDU is therefiore a synchronous operation.
In order to provision scaling to many clients, we are trying to reimplement it using NIO.
We use a Selector to wait for requests, and once accepted, we register the Selector with the created SocketChannel (one per client).
One single thread dequeues reads selected by the Selector, but we are still trying to read using the synchronous BufferredReader.
When a SocketChannel has readable data, we create a Buffered reader like this:
BufferedReader reader =new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));
String pdu = reader.readLine();// throws IllegalBlockingModeException
}
And as you probably expect, we get an IllegalBlockingModeException when reading the line (synchronous operation) over the (asynchronous) socket.
If my understanding is correct, the SocketChannel has to be put in non-blocking mode to be selectable by the Selector (otherwise the register(...) call throws anIllegalBlockingStateException), but it cannot be read synchronously in this non-blocking mode.
Is there any way I can connect a BufferedReader to a non-blocking SocketChannel somehow?
There would be an alternative approach, where the listeing thread reads the data from the SocketChannel into a ByteBuffer, then stuffs those bytes into a PipedOutputStream, and build a reader over a PipedInputStream.
The problem is that in this case, we need, again, one thread per client to read the data froml the reader...
There's a third approach, where we would use the "attachment" feature of SocketChannel.register() and SelectedKey; in this approach, the attachment could be a stringBuffer; each time the Selector warns us that data is readable, the data would be read from the SocketChannel into a ByteBuffer. then added to the StringBuffer. We would have to analyze the StringBuffer's content to find out whether it contains a whole line, and only then extract this line as the "PDU".
Is this a recommended approach?
Thanks in advance, and regards,
J.
Message was edited by: jduprez (some code markers had been swallowed)
Message was edited by:
jduprez

