How do I limit reading a line at a time from a SocketChannel InputStream using Java NIO?

I would recommend using something like Apache Mina or Grizzly. Both allow you to encapsulated the protocol aspect of your problem so you only have to handle consumable data.

Up vote 0 down vote favorite share g+ share fb share tw.

I am trying to write a Websockets client and server. Initially the connection is HTTP and the Websockets handshake uses HTTP headers to indicate that an upgrade to a new protocol is necessary on the connection. I want to read in the set of HTTP headers from the SocketChannel and, if an upgrade is indicated, switch over to a different library for handling Websockets and from that point on handle the SocketChannel streams completely differently, as a set of frames rather than lines delimited with \r\n.

I know I can read an arbitrary number of bytes into a ByteBuffer, but a Websockets frame may have been sent with the handshake and I don't want to be passing off half-consumed buffers between these sections of code. What I want is to read from the socket only the data up to and including sequence "\r\n\r\n". Any data beyond that I want to leave in the SocketChannel object input stream.

What is the recommended way to do this? Get the input stream from the SocketChannel and wrap it in a buffered reader? Would this interact properly with NIO, particularly non-blocking uses?

Could I drop the buffered reader from the input stream once the blank line was detected and still have all the frame data available when the channel is passed to the Websockets code? Or perhaps I need to read byte-by-byte (or 4 byte chunks with smaller buffers if some of the target "\r\n\r\n" characters appear at the end of the chunk) and build up my header strings that way. Or maybe some combination of manipulating mark, limit and position would allow the input stream to get back data it had previously read into the ByteBuffer provided the buffer was allocated directly.

Any advice would be greatly appreciated. Java nio readline websocket bytebuffer link|improve this question asked May 2 '11 at 21:36sockets-to-me1266.

– Peter Lawrey May 2 '11 at 22:03 A SocketChannel doesn't have an input stream. It has a receive buffer, is that what you meant? – EJP May 4 '11 at 10:51 Peter Lawley: I don't want to pass a half-consumed buffer because it increases the coupling between the handshake code and the websocket frame code.

They both have to work with the SocketChannel, so that has to be passed anyway. If I can avoid passing yet another object between them (not to mention state for the buffer like whether it needs flipping) I think that is much cleaner. – sockets-to-me May 4 '11 at 17:25 EJP: I believe you can get an Input Stream from a SocketChannel by calling .socket().getInputStream().

That is what I meant. – sockets-to-me May 4 '11 at 17:28 But you have to put the channel into blocking mode first, and deregister it from the Selector before that, and therefore read in a separate thread, and undo all that afterwards ... You may as well not use NIO at all. – EJP May 4 '11 at 0:10.

I would recommend using something like Apache Mina or Grizzly. Both allow you to encapsulated the protocol aspect of your problem so you only have to handle consumable data. However if you want a quick and dirty way: The basic idea though is yeah you need to read the data as it comes in.

If it is not readily usable, I usually create some appendable structure (StringBuilder for something simple) to the SelectionKey that is in the selector. After each read I would append the data to the builder, and if you detect a usable header, slice it out of the buffer and pass it up stream (preferably on a worker thread). Keep doing this and whatever is upstream should be able to react accordingly.

Hope that helps. So usually you have a structure like this: ByteBuffer reUsableBuffer = ByteBuffer. AllocateDirect(5120); Selector selector = Selector.open(); ServerSocketChannel channel = .. // wherever you get it from channel.

Register(selector, SelectionKey. OP_ACCEPT); Executor executor = Executors. NewThreadPoolExecutor(); while(selector.isOpen()) { int numKey = selector.select(); for (SelectionKey key: selector.selectedKeys()) { if (key.isAcceptable()) { /// Sort of included for completeness but you get the idea ServerSocketChannel server = (ServerSocketChannel)key.channel(); SocketChannel channel = server.accept(); channel.

Register(selector, SelectionKey. OP_READ | Selection. OP_WRITE, new StringBuilder()); } if (key.isReadable()) { // READ the data reUsableBuffer.clear(); // You have to keep track of previous state.

// NIO makes no guarantees of anything StringBuilder builder = key.attachment(); SocketChannel socketChannel = (SocketChannel)key.channel(); int readCount = socketChannel. Read(reUsableBuffer); if (readCount > 0) { reUsableBuffer.flip(); byte subStringBytes = new bytereadCount; reUsableBuffer. Read(subStringBytes); // Assuming ASCII (bad assumption but simplifies the example) builder.

Append(new String(substringBytes)); Command commands = removeCommands(builder); // Deal with your commands in some async manor defined by you executor. Execute(new Task(commands)); } } selector.selectedKeys().clear(); } .... } // // Parse out the commands and return them, also remove traces of them in the // the builder, such that for a string, "COMMAND, COMMAND, COM" // an array of 2 should be returned with a left over buffer of "COM" public Command parseCommands(StringBuilder s) { ... }.

Thanks for the suggestion about Mina or Grizzly. Eventually I want to make the transport section of the library replaceable so that it can be used in a variety of contexts like that. But to start with, I'm looking for something simple that doesn't rely on another server framework.

– sockets-to-me May 4 '11 at 17:37 As for your idea about an appendable structure, that sounds like more context to shift around which was what I didn't like about passing the ByteBuffer around. Or are you suggesting a separate thread that does nothing but build these structures and then passes them off to another thread that translates them to handshakes or frames? – sockets-to-me May 4 '11 at 17:39 so sort of included some rough code (haven't compiled it our tried to run it (no error handling included)), that should give you the idea of what I am hinting out.

In NIO you are basically managing a state machine, and you will have to inherently manage state :) So without a ByteBuffer being attached to keys or something to backtrack previous state, you will lose data. If you want to use streams and do a full readLine() then it will block and if that is on your thread using the selector then that is going to degrade your overall ability to service connections. – Greg May 4 '11 at 19:33.

I would wrap the socket InputStream with an appropriate line oriented reader, such as LineNumberReader. Under the hood these readers read a byte at a time. I would not use a BufferedReader for this, for the reason you state.

EJP: Actually, I did mention this although I used "buffered reader" instead of the class name. – sockets-to-me May 4 '11 at 17:29 user726092: Thanks for the suggestion. I would not have thought of this seemingly irrelevant option, and I certainly wasn't aware that they read a byte at a time.

Is that portable? – sockets-to-me May 4 '11 at 17:35.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions