NIO SocketChannel non-blocking read

Hello.
I'm not sure a resembling message has already been posted in a forum. In such a case, thanks for redirecting to it.
Goals :
A selector is used by a main server thread to make accept and read operations non-blocking.
When a connection is accepted, the newly created socket channel is configured as non-blocking, and a key is added to the selector with the OP_READ flag.
When data are available on sockets, a new task (runnable) is created and submitted to a thread pool.
When a thread is ready to process the request, a pre-allocated bytebuffer is used to read arriving data.
The problem :
When the bytebuffer capacity is less than the received bytes count, the read method on the socket channel interrupts the selector on the same selection key. In response to this event, a new task is initiated, interferring with the previous one.
As expected according to my concurrency policy (ie. with a pool of threads), several requests are processed by parallel threads. To avoid unsafe accesses, i added a synchronized statement on the channel blocking lock, and it seems to works fine. But a better way should exist...
Questions :
Is this the expected behavior ?
Is there any other way to read received data with a small buffer ?
The full copy of the source code :
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
import net.moon.threads.*;
public class Nio1 {
     static class Request {
          boolean isCompleted = false;
          int inputs = 0;
          Set workers = new HashSet();
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          byte p = 0;
          boolean isCompleted() {
               return isCompleted;
          void countInput() {
               inputs++;
          void append(final ByteBuffer byteBuffer) {
               if (isCompleted)
                    throw new IllegalStateException("Request is already completed");
               workers.add(Thread.currentThread());
               while (byteBuffer.hasRemaining()) {
                    byte b = byteBuffer.get();
                    baos.write(b);
                    if ((b == '\r') && (p == '\n'))
                         isCompleted = true;
                    p = b;
          int inputs() {
               return inputs;
          Thread[] workers() {
               return (Thread[]) workers.toArray(new Thread[0]);
          int size() {
               return baos.size();
          byte[] getData() {
               return baos.toByteArray();
          void reset() {
               isCompleted = false;
               inputs = 0;
               baos.reset();
               workers.clear();
     static private class RequestTask implements Runnable {
     private final static Charset charset = Charset.forName("US-ASCII");
          private final Server server;
          private final SelectionKey selectionKey;
          RequestTask(final Server server, final SelectionKey selectionKey) {
               this.server = server;
               this.selectionKey = selectionKey;
          public void run() {
               log("*** Processing input...");
               try {
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
synchronized(channel.blockingLock()) {
                    Request request = (Request) selectionKey.attachment();
                    request.countInput();
                    State state = getState();
                    log("Reading first...");
                    int c = channel.read(state.byteBuffer);
                    log("... Read first : " + c);
                    if (c > 0) {
                         for(;;) {
                              state.byteBuffer.flip();
                         request.append(state.byteBuffer);
                              state.byteBuffer.clear();
                              if (c < state.byteBuffer.capacity()) break;
                              log("Reading next...");
                              c = channel.read(state.byteBuffer);
                              log("... Read next : " + c);
                              if (c <= 0) break;
                         if (request.isCompleted()) {
                              log("Request completed : " + request.inputs());
                              StringBuffer bodyBuffer = new StringBuffer();
                              bodyBuffer.append("-----------------------------\r\n");
                              bodyBuffer.append("Request processed in " + request.inputs() + " inputs\r\n");
                              bodyBuffer.append("Request size is " + request.size() + " bytes\r\n");
                              bodyBuffer.append("Participating workers :\r\n");
                              Thread[] workers = request.workers();
                              for (int i = 0; i < workers.length; i++)
                                   bodyBuffer.append(" * " + workers[i] + "\r\n");
                              bodyBuffer.append("-----------------------------\r\n");
                              StringBuffer headerBuffer = new StringBuffer();
                              headerBuffer.append("HTTP/1.1 200 OK\r\n");
                              headerBuffer.append("Server: NIO Server 1\r\n");
                              headerBuffer.append("Content-Type: text/plain\r\n");
                              headerBuffer.append("Content-Length: ").append(request.size() + bodyBuffer.length()).append("\r\n");
                              headerBuffer.append("\r\n");
                         CharsetEncoder encoder = charset.newEncoder();
                              channel.write(encoder.encode(CharBuffer.wrap(headerBuffer)));
                              channel.write(encoder.encode(CharBuffer.wrap(bodyBuffer)));
                              channel.write(ByteBuffer.wrap(request.getData()));
                              request.reset();
                    if (c < 0) {
                         selectionKey.attach(null);
                         selectionKey.cancel();
                         log("!!! Connection terminated for channel " + channel);
               catch(final Exception x) {
                    x.printStackTrace();
               log("*** Request processed...");
          private State getState() {
               State state = (State) server.taskManager.getCurrentWorkerState();
               if (state == null) {
                    state = new State();
                    server.taskManager.setCurrentWorkerState(state);
               else {
                    state.byteBuffer.clear();
               return state;
          private void log(final String text) {
               System.out.println(Thread.currentThread() + " : " + text);
          static class State {
               ByteBuffer byteBuffer = ByteBuffer.allocateDirect(32);
     static private class Server implements Runnable {
          private final int port;
          private Thread worker;
          private FIFOTaskManager taskManager;
          Server(final int port) {
               this.port = port;
               worker = null;
          synchronized void start() throws Exception {
               if (worker == null) {
                    log("Starting the server...");
                    taskManager = new FIFOTaskManager("Nio1Workers", 24);
                    worker = new Thread(this);
                    worker.start();
                    synchronized(worker) {
                         try {
                              worker.wait();
                         catch(InterruptedException x) {
                    log("Server started !");
          public void run() {
               try {
                    log("Server is starting...");
                    Selector selector = SelectorProvider.provider().openSelector();
                    log("Creating listener on port " + port);
                    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                    serverSocketChannel.configureBlocking(false);
                    InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
                    serverSocketChannel.socket().bind(inetSocketAddress);
                    SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
                    synchronized(worker) {
                         worker.notify();
                    while (selector.select() >= 0) {
                         Set readyKeys = selector.selectedKeys();
                         log("Keys are ready : " + readyKeys.size());
                         for (Iterator i = readyKeys.iterator(); i.hasNext(); ) {
                              SelectionKey selectedKey = (SelectionKey) i.next();
                              if (selectedKey.isAcceptable()) {
                                   ServerSocketChannel ssc = (ServerSocketChannel) selectedKey.channel();
                                   SocketChannel sc = ssc.accept();
                                   sc.configureBlocking(false);
                                   SelectionKey sk = sc.register(selector, SelectionKey.OP_READ);
                                   sk.attach(new Request());
                                   log("Connection accepted for channel " + sc);
                              else if (selectedKey.isReadable()) {
                                   log("Key ready for input : " + selectedKey);
                                   taskManager.execute(new RequestTask(this, selectedKey));
                              i.remove();
                         readyKeys = null;
                    log("Server loop interrupted !");
               catch(Exception x) {
                    x.printStackTrace();
          private void log(final String text) {
               System.out.println("SERVER: " + text);
     public static void main(final String[] args) throws Exception {
          Server server = new Server(9001);
          server.start();

Thanks for the trick. I hope the code will be more readable than my sockets !
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
import net.moon.threads.*;
public class Nio1 {
     static class Request {
          boolean isCompleted = false;
          int inputs = 0;
          Set workers = new HashSet();
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          byte p = 0;
          boolean isCompleted() {
               return isCompleted;
          void countInput() {
               inputs++;
          void append(final ByteBuffer byteBuffer) {
               if (isCompleted)
                    throw new IllegalStateException("Request is already completed");
               workers.add(Thread.currentThread());
               while (byteBuffer.hasRemaining()) {
                    byte b = byteBuffer.get();
                    baos.write(b);
                    if ((b == '\r') && (p == '\n'))
                         isCompleted = true;
                    p = b;
          int inputs() {
               return inputs;
          Thread[] workers() {
               return (Thread[]) workers.toArray(new Thread[0]);
          int size() {
               return baos.size();
          byte[] getData() {
               return baos.toByteArray();
          void reset() {
               isCompleted = false;
               inputs = 0;
               baos.reset();
               workers.clear();
     static private class RequestTask implements Runnable {
         private final static Charset charset = Charset.forName("US-ASCII");
          private final Server server;
          private final SelectionKey selectionKey;
          RequestTask(final Server server, final SelectionKey selectionKey) {
               this.server = server;
               this.selectionKey = selectionKey;
          public void run() {
               log("*** Processing input...");
               try {
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
synchronized(channel.blockingLock()) {
                    Request request = (Request) selectionKey.attachment();
                    request.countInput();
                    State state = getState();
                    log("Reading first...");
                    int c = channel.read(state.byteBuffer);
                    log("... Read first : " + c);
                    if (c > 0) {
                         for(;;) {
                              state.byteBuffer.flip();
                             request.append(state.byteBuffer);
                              state.byteBuffer.clear();
                              if (c < state.byteBuffer.capacity()) break;
                              log("Reading next...");
                              c = channel.read(state.byteBuffer);
                              log("... Read next : " + c);
                              if (c <= 0) break;
                         if (request.isCompleted()) {
                              log("Request completed : " + request.inputs());
                              StringBuffer bodyBuffer = new StringBuffer();
                              bodyBuffer.append("-----------------------------\r\n");
                              bodyBuffer.append("Request processed in " + request.inputs() + " inputs\r\n");
                              bodyBuffer.append("Request size is " + request.size() + " bytes\r\n");
                              bodyBuffer.append("Participating workers :\r\n");
                              Thread[] workers = request.workers();
                              for (int i = 0; i < workers.length; i++)
                                   bodyBuffer.append(" * " + workers[i] + "\r\n");
                              bodyBuffer.append("-----------------------------\r\n");
                              StringBuffer headerBuffer = new StringBuffer();
                              headerBuffer.append("HTTP/1.1 200 OK\r\n");
                              headerBuffer.append("Server: NIO Server 1\r\n");
                              headerBuffer.append("Content-Type: text/plain\r\n");
                              headerBuffer.append("Content-Length: ").append(request.size() + bodyBuffer.length()).append("\r\n");
                              headerBuffer.append("\r\n");
                             CharsetEncoder encoder = charset.newEncoder();
                              channel.write(encoder.encode(CharBuffer.wrap(headerBuffer)));
                              channel.write(encoder.encode(CharBuffer.wrap(bodyBuffer)));
                              channel.write(ByteBuffer.wrap(request.getData()));
                              request.reset();
                    if (c < 0) {
                         selectionKey.attach(null);
                         selectionKey.cancel();
                         log("!!! Connection terminated for channel " + channel);
               catch(final Exception x) {
                    x.printStackTrace();
               log("*** Request processed...");
          private State getState() {
               State state = (State) server.taskManager.getCurrentWorkerState();
               if (state == null) {
                    state = new State();
                    server.taskManager.setCurrentWorkerState(state);
               else {
                    state.byteBuffer.clear();
               return state;
          private void log(final String text) {
               System.out.println(Thread.currentThread() + " : " + text);
          static class State {
               ByteBuffer byteBuffer = ByteBuffer.allocateDirect(32);
     static private class Server implements Runnable {
          private final int port;
          private Thread worker;
          private FIFOTaskManager taskManager;
          Server(final int port) {
               this.port = port;
               worker = null;
          synchronized void start() throws Exception {
               if (worker == null) {
                    log("Starting the server...");
                    taskManager = new FIFOTaskManager("Nio1Workers", 24);
                    worker = new Thread(this);
                    worker.start();
                    synchronized(worker) {
                         try {
                              worker.wait();
                         catch(InterruptedException x) {
                    log("Server started !");
          public void run() {
               try {
                    log("Server is starting...");
                    Selector selector = SelectorProvider.provider().openSelector();
                    log("Creating listener on port " + port);
                    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                    serverSocketChannel.configureBlocking(false);
                    InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
                    serverSocketChannel.socket().bind(inetSocketAddress);
                    SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
                    synchronized(worker) {
                         worker.notify();
                    while (selector.select() >= 0) {
                         Set readyKeys = selector.selectedKeys();
                         log("Keys are ready : " + readyKeys.size());
                         for (Iterator i = readyKeys.iterator(); i.hasNext(); ) {
                              SelectionKey selectedKey = (SelectionKey) i.next();
                              if (selectedKey.isAcceptable()) {
                                   ServerSocketChannel ssc = (ServerSocketChannel) selectedKey.channel();
                                   SocketChannel sc = ssc.accept();
                                   sc.configureBlocking(false);
                                   SelectionKey sk = sc.register(selector, SelectionKey.OP_READ);
                                   sk.attach(new Request());
                                   log("Connection accepted for channel " + sc);
                              else if (selectedKey.isReadable()) {
                                   log("Key ready for input : " + selectedKey);
                                   taskManager.execute(new RequestTask(this, selectedKey));
                              i.remove();
                         readyKeys = null;
                    log("Server loop interrupted !");
               catch(Exception x) {
                    x.printStackTrace();
          private void log(final String text) {
               System.out.println("SERVER: " + text);
     public static void main(final String[] args) throws Exception {
          Server server = new Server(9001);
          server.start();
}

Similar Messages

  • Implementing non-blocking read

    Hi all
    I have some doubts about implementing non-blocking io in my application.
    I am using Jsch library (an ssh implementation) to open an ssh connection with a host. The API only provides me with methods to open a connection and retreive the input & output streams. I want to make my read on inputstream non-blocking.In such a case is it possible to use nio for the purpose?
    If it's not possible then I am planning to use threading to make read() non-blocking. Here also i need some clarifications. I am planning to use a ThreadPoolExecutor to create a thread pool for reading data. SO whenever i have a read i'll assign this task to the pool which will use one of the free threads to execute the inputStresm.read().
    Now the question is if one of the threads in this pool blocks forever during a read since it didn't get any response from the other side, is there a way to stop that read and make that thread free again to execute more tasks? or will the thread block forever till the application is closed?
    In my case i cannot afford to have too many such blocked threads, since this application will not be restarted very often. Once it is started it can go on for may be days or months.
    Please suggest what would be best in my case taking into account performance as most important factor.
    Thanks in advance.
    Anu

    endasil wrote:
    First of all, let me state that I agree with the others in saying that I don't fully agree with your premises.
    That said, I believe that this does a non-blocking read based on the contract of InputStream.available() and .read(byte[], int, int):
    private int nonBlockingRead(InputStream in, byte[] buffer) throws IOException {
    return in.read(buffer, 0, Math.min(in.available(), buffer.length));
    If the InputStream is obtained from a JSSE socket then it is my understanding that available() always returns zero. This is allowed under the InputStream.available() contract as defined in the Javadoc - http://java.sun.com/javase/6/docs/api/java/io/InputStream.html#available() . If I am right then your code will never read anything from a JSSE socket InputStream and I would suspect that Jsch is using JSSE sockets.

  • Java.nio selector non-blocking IO question

    Hi,
    I am designing an interactive server where multiple clients can log on and communicate with the server. I designed a protocol that the client/server use to talk to each other. My server runs a Selector to monitor a ServerSocket, accepting connections and reading continuously from clients.
    Now my question is, since read() on ServerChannel are non-blocking using selector, how can I be sure that my entire protocol message will be read each time selector wakes up? For example, a slow client sends me a 5kb message, in one write() command, can I be sure that I will be able to read the entire message in one non-blocking read() command as well? If not, then the design becomes much more complicated, as I have to pipe each client's input into a handler thread that performs blocking i/o to read a protocol message one at a time. If I do that, then I might as well not use select() at all.
    I did some preliminary tests, and it seems that for my purpose (message of size <= 50kb), a read() command will always be able to read the entire message. But I can't find any documentation on this subject. My guess is that I cannot trust non-blocking I/O as well, which means it does not fit my purpose.
    Any help will be much appreciated.
    Thanks,
    Frank

    You can't be sure a read() will read in all the data from a client in one call.
    For example, say your message from the client to the server is of the following format. <start>message here<end>, where <start> indicates the start of a message and <end> the end of the message. In one read() call you might get "<start>message he". Your server would recognize this is partially correct but it needs the rest of the message. The server would store this and on the second read() you might get "re<end>" for the complete message.
    The purpose of non-blocking I/O is so you don't have to wait around for the second part of the message, you can process other client messages while the first client finishes sending their message. This way other clients aren't waiting around while you(the server) sit and wait for client 1 to finish sending it's data.
    So basically there is no gaurantee you will get a whole message intact. Your protocol will have to deal with partial messages, recognize them, store the partial message in a buffer, and on subsequent reads get the rest of the message.
    Nick

  • Non-blocking read from an InputStream??

    Hello all, I have a bit of a problem. I have a GUI based app that, through the mindterm SSH classes, runs a "tail -f /var/log/somelog" command on a *nix server. The purpose of the app is to make looking through the log's easier for the non-computer lay-person. The problem is that if they click the stop button to stop the output of the tail it doesn't actually stop that thread until the next line is appended to the end of the log file. That could be a second or an hour. So what I need is a way to somehow stop that tail -f command when the user hits stop and not have to wait for the read to occur.
    What I'm working with is a com.mindbright.util.InputStreamPipe that is a subclass of java.io.InputStream. I've tried several things. Such as the seda.nbio.NonblockingInputStream which gives me a runtime classCastException when trying to cast the com.mindbright.util.InputStreamPipe to a seda.nbio.NonblockingInputStream. I've tried creating a java.nio.channels.ReadableByteChannel and using it's read method but that also blocks.
    So my question is, does anyone have any clever solutions to this particular problem? I thought the way to beat it was to find some mechanism to do a read that will just get passed by if there's nothing to read then have it wait an arbitrary amount of time before reading again. So the longest the user would have to wait would be that arbitrary amount of time. But I don't know how to implement this or if it's even a good way to do it.
    Thanks in advance!

    Thanks for the help dubwai. I actually found a way to accomplish this without any non-blocking balony.
    public void run () {
                            try {
                                    java.io.InputStream is = tbs.getConsoleOut();
                                    java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(is));
                                    String line = null;
                                    // continue is a volatile boolean that gets set to false when user clicks stop
                                    while ( cont ) {
                                            if ( is.available() > 0 ) {
                                                    line = in.readLine();
                                                    System.out.println("in while: "+line);
                                            } // end
                                            else {
                                                    try {
                                                            java.lang.Thread.sleep(500);
    } // end try
                                                    catch ( java.lang.InterruptedException ie ) {
                                                            System.err.println("Error sleeping: "+ie);
                                                    } // end catch
                                            } // end else
                                    } // end while
                                    is.close(); in.close();
                                    System.out.println("After while");
                                    System.exit(0);
                            } // end try
                            catch ( Exception e ) {
                                    System.err.println("Error reading lines: "+e);
                            } // end catch
                    } // end runThis seems to work on a few trial runs.. Does anyone see any possible random timing issues from this??

  • NIO: Strange problem when using ByteBuffer with non-blocking SocketChannel

    Hi,
    I have a server that uses multiplexed, non-blocking I/O with java.nio. When a client connects, the server waits for the message: <system cmd="knock"/>, returns a message and disconnects the client. The clients are shortly serviced in less than a second.
    But the server newer receive anything from about 20% of the clients - even though it is sent. Or with other words: it is received and the data is contained in the ByteBuffer - SocketChannel.read(ByteBuffer) - but a call to ByteBuffer.remaing() returns 0 !!
    ByteBuffer receiveBuf = ByteBuffer.allocate(65536);
    receiveBuf.clear(); // the code is elsewhere used for longer living clients
    int readBytes = channel.read(receiveBuf);
    receiveBuf.flip();
    StringBuffer sb = new StringBuffer();
    System.out.println(" * Remaining: "+receiveBuf.remaining()); // writes: ' * Remaining: 0'
    System.out.println(" * Received: "+new String(receiveBuf.array())); // writes: ' * Received: <system cmd="knock"/>'
    while(receiveBuf.remaining() >= 2) {
      byte b = receiveBuf.get();
      sb.append((char)b);
    System.out.println(" * sb content: "+sb.toString()); // writes: ' * sb content: 'The ByteBuffer clearly receives the correct data, but the ByteBuffer.remaining() returns 0 and therefore the StringBuffer will never have any content.
    The problem seems to occur randomly and for about 20% of the clients (simulated from the same computer and therefore has the same bandwidth and so on).
    Anyone knows what is going on, and how to solve the problem !?

    It's always possible in any read that the number of bytes read is less than the number of bytes requested. You need to keep reading until you have got everything you expected, and cope with every possible error condition on each iteration.
    EJP

  • Non-blocking Vectored read from SocketChannel fails

    Hi.
    Please look at the code example:
    ByteBuffer tmp1 = ByteBuffer.allocate(500);
    ByteBuffer tmp2 = ByteBuffer.allocate(500);
    ByteBuffer[] tmp = {tmp1, tmp2};
    while ((count = socketChannel.read(tmp)) > 0) {
    + "bytes.");
    When I run this code, (using non-blocking socket channel), the first buffer is read ok, but on the second round of the while loop, I get an IOException, saying: "a non blocking socket operation could not be completed immediately".
    If I put 'tmp1' instead of 'tmp' in the read(), (i.e - use a normal buffer), the read successfully finishes.
    Why?
    I found nothing in the documentation, and in the 'Java NIO' book (Ron Hitchens).
    Help?
    Thanks.

    Please ignore the + "bytes."); inside the while.

  • NIO Non-Blocking Server not Reading from Key

    I have created a NIO non blocking server (below) and it will not pick up any input from the client.... My log doesnt even show that it enters the readKey() method, so it must be something before. Any help would be appreciated.
    Scott
    package jamb.server;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.ClosedChannelException;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.nio.channels.spi.SelectorProvider;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.logging.Logger;
    import java.util.prefs.Preferences;
    import jamb.server.client.Client;
    public class Server {
            private Selector selector;
            private ServerSocketChannel serverChannel;
            private static Logger logger = Logger.getLogger("jamb.server");
            private static Preferences prefs =  Preferences.systemRoot().node("/jamb/server");
            public void init() {
                    logger.entering("jamb.server.Server", "init");
                    //Get a selector...
                    try {
                            selector = SelectorProvider.provider().openSelector();
                            //Open the SocketChannel and make it non-blocking...
                            serverChannel = ServerSocketChannel.open();
                         serverChannel.configureBlocking(false);
                            //Bind the server to the port....
                            int port = prefs.getInt("Port", 4000);
                            logger.config("Server configured on port " + port + " (default: 4000)");
                         InetSocketAddress isa = new InetSocketAddress(
                                    InetAddress.getLocalHost(), port);       
                         serverChannel.socket().bind(isa);
                    } catch (IOException ioe) {
                            logger.severe ("IOException during server initialization!");
                    logger.exiting("jamb.server.Server", "init");
            public void run() {
                    logger.entering("jamb.server.Server", "run");
                    int bufferSize = prefs.getInt("BufferSize", 8);
                    logger.config("Buffer size set to " + bufferSize + " (default: 8)");
                    SelectionKey acceptKey = null;
                    try {
                            acceptKey = serverChannel.register(
                                    selector, SelectionKey.OP_ACCEPT);
                    } catch (ClosedChannelException cce) {
                    try {
                            while (acceptKey.selector().select() > 0) {
                                    Set readyKeys = selector.selectedKeys();
                                    Iterator i = readyKeys.iterator();
                                    while (i.hasNext()) {
                                            //logger.finest("Processing keys...");
                                            //Get the key from the set and remove it
                                            SelectionKey currentKey = (SelectionKey) i.next();
                                            i.remove();
                                            if (currentKey.isAcceptable()) {
                                                    logger.finest("Accepting key...");
                                                    acceptKey(currentKey);
                                            } else if (currentKey.isReadable()) {
                                                    logger.finest("Reading key...");
                                                    readKey(currentKey, bufferSize);
                                            } else if (currentKey.isWritable()) {
                                                    //logger.finest("Writing key...");
                                                    writeKey(currentKey);
                    } catch (IOException ioe) {
                            logger.warning("IOException during key handling!");
                    logger.exiting("jamb.server.Server", "run");
            public void flushClient (Client client) {
                    try {
                            ByteBuffer buf = ByteBuffer.wrap( client.getOutputBuffer().toString().getBytes());
                            client.getChannel().write(buf);
                    } catch (IOException ioe) {
                            System.out.println ("Error writing to player");
                    client.setOutputBuffer(new StringBuffer());
            private void acceptKey (SelectionKey acceptKey) {
                    logger.entering("jamb.server.Server", "acceptKey");
                    //Retrieve a SocketChannel for the new client, and register a new selector with
                    //read/write interests, and then register
                    try {
                            SocketChannel channel =  ((ServerSocketChannel) acceptKey.channel()).accept();
                            channel.configureBlocking(false);
                            SelectionKey readKey = channel.register(
                                    selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE  );
                            readKey.attach(new Client(this, channel));
                    } catch (IOException ioe) {
                            System.out.println ("Error accepting key");
                    logger.exiting("jamb.server.Server", "acceptKey");
            private void readKey (SelectionKey readKey, int bufSize) {
                    logger.entering("jamb.server.Server", "readKey");
                    Client client = (Client) readKey.attachment();
                    try {
                            ByteBuffer byteBuffer = ByteBuffer.allocate(bufSize);
                            int nbytes = client.getChannel().read( byteBuffer );
                            byteBuffer.flip();
                            Charset charset = Charset.forName( "us-ascii" );
                            CharsetDecoder decoder = charset.newDecoder();
                            CharBuffer charBuffer = decoder.decode(byteBuffer);
                            String text = charBuffer.toString();
                            client.getInputBuffer().append(text);
                            if ( text.indexOf( "\n" ) >= 0 )
                                    client.input();
                    } catch (IOException ioe) {
                            logger.warning("Unexpected quit...");
                            client.disconnect();
                    logger.exiting("jamb.server.Server", "readKey");
            private void writeKey (SelectionKey writeKey) {
                    //logger.entering("jamb.server.Server", "writeKey");
                    Client client = (Client) writeKey.attachment();
                    if (!client.isConnected()) {
                            client.connect();
                    //logger.exiting("jamb.server.Server", "writeKey");

    From my own expierence with the NIO (Under Windows XP/ jdk1.4.1_01); you can't seem to set READ and WRITE at the same time.
    The program flow I usually end up with for a echo server is:
    When the selector.isAcceptable(): accept a connection; register for READs
    In the read event; write the incoming characters to a buffer; register for a WRITE and add the buffer as an attachment.
    In the write event; write the data to the socket If all the data was written; register for a READ; otherwise register for another WRITE so that you can write the rest.
    Not sure if that the "proper" way; but it works well for me.
    - Chris

  • Non-Blocking SocketChannel read give Connection timed out

    Hi,
    My program is using Non-Block NIO SocketChannel for both Server and Client sides. However, if the connection between server and client has been idle for a while, when the client try to communicate with server, it gets blocked for a while (15 minutes) and then receives the following exception:
    java.io.IOException: Connection timed out
         at sun.nio.ch.FileDispatcher.read0(Native Method)
         at sun.nio.ch.SocketDispatcher.read(Unknown Source)
         at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
         at sun.nio.ch.IOUtil.read(Unknown Source)
         at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
    How can this be since the read is in Non-Blocking mode? Also, is there anyway to determine the timeout without being blocked?

    This would mean that you are trying to read from the socket without having properly completed the connection, which timed out. I would say you are connecting in non-blocking mode but not calling finishConnect() when you get OP_CONNECT.

  • SO timeout relevance in non-blocking NIO ServerSocketChannel

    I converted a threaded blocking server from using the standard blocking IO with a thread for each connection to using non-blocking NIO channels. Works great but I'm trying to understand the SO timeout relevance in the context of non-blocking NIO channels. Is there any relevance and should I set an SO timeout on the ServerSocket associated with a ServerSocketChannel and if so how should I handle it?

    No. Socket timeouts are for blocking mode. If you need timeouts in non-blocking mode you have to do them yourself, taking advantage of the Selector.select(long timeout) method and keeping track of activity times per channel yourself. You should use that select() method anyway, rather than just blocking indefinitely, as it gives you a chance to catch up on housekeeping, dead channels, etc. For example as a very naive approach if nothing happens in say a select timeout of 10 minutes you might want to close all accepted SocketChannels.

  • Interrupt() on SocketChannel blocking read()

    I'm having a problem gracefully shutting down a thread while it is blocked in a SocketChannel read() function. According to the nio.channel and Thread docs, if a thread is blocked in a SocketChannel read() method and another thread calls the interrupt() method on the first thread, the first thread should return from the blocked read() call after the SocketChannel has been closed, and the second thread should immediately return from the interrupt call no matter what the state of the first thread.
    What's actually happening is that the second thread is locking up in the interrupt() call and the first thread is not returning from the read() call. I'm not sure if I'm missing anything here, but I've not seen any forum discussions or bug reports on this.
    Can anyone shed some light on this behavior? The following demonstration code shows this thread shutdown behavior in two modes:
    No arguments simply spins a thread that uses sleep() to display a line every second. This shuts down as expected.
    Specifying a hostname and port number spins a thread that connects to that address with a SocketChannel and loops on read() calls to that channel. This is what locks up when you try to interrupt() the spun thread.
    Demonstration code JDK1.4.0
    * ThreadExp.java
    * This app works in one of two modes:
    *   1: Invoked with no arguments it will spin a thread that
    *      displays a line every second.
    *   2: Invoked with a hostname and a port number it will spin a thread that
    *      opens a SocketChannel to that address and loops on reading the channel
    *      until it is closed or interrupted.
    * In either case the main thread runs a command interpreter allowing you to:
    *   (return)  Display the threads.
    *   stop      Stop the spun thread.
    *   quit      Quit the application and stop any active thread.
    * This works fine in mode 1, but in mode 2 the main thread locks up in the
    * interrupt() call to the spun thread while the spun thread is blocked in
    * a read() function on the channel. According to the SocketChannel and
    * Thread docs, the call to interrupt() on the spun thread should interrupt
    * the blocked read() call after closing the socket connection. The interrupt
    * call should immediatly return.
    import java.io.*;
    import java.nio.*;
    import java.nio.channels.*;
    import java.nio.charset.*;
    import java.net.*;
    public
    class ThreadExp
    implements Runnable {
       private volatile Thread thread = null;
       String hostname;
       int    port;
       public
       ThreadExp(String hostname, int port)
          this.hostname = hostname;
          this.port     = port;
          thread = new Thread(this, "ThreadExpThread");
          thread.start();
       public
       void
       stop()
          if (thread == null) return;
          Thread tmpThread = thread;
          thread = null;
          System.out.println("Interrupting thread...");
          tmpThread.interrupt();
       public
       void
       run()
          Charset        charset = Charset.forName("US-ASCII");
          CharsetDecoder decoder = charset.newDecoder();
          SocketChannel  channel = null;
          ByteBuffer     buf     = ByteBuffer.allocateDirect(1024);
          try {
             if (hostname != null) {
                System.out.println("Opening channel...");
                channel = SocketChannel.open(
                   new InetSocketAddress(InetAddress.getByName(hostname), port)
             Thread thisThread = Thread.currentThread();
             while (thread == thisThread) {
                if (hostname != null) {
                   buf.clear();
                   System.out.println("Reading...");
                   int len = channel.read(buf);
                   System.out.println("Read " + len);
                   if (len < 0) break;
                   buf.flip();
                   System.out.print(decoder.decode(buf));
                } else {
                   System.out.println("  .");
                   thread.sleep(1000);
          } catch (InterruptedException e) {
             System.out.println("Thread interupted.");
          } catch (IOException e) {
             e.printStackTrace();
          } finally {
             if (channel != null) {
                try {
                   System.out.println("Closing channel...");
                   channel.close();
                   channel = null;
                } catch (IOException e) {
                   e.printStackTrace();
          System.out.println("Exiting thread.");
       public static
       void
       main(String args[])
          System.out.println(
               "(return)  Display threads\n"
             + "stop      Stop the spun thread\n"
             + "quit      Quit this app and stop any active thread"
          ThreadExp app = null;
          try {
             if (args.length == 2) {
                app = new ThreadExp(args[0], Integer.parseInt(args[1]));
             } else {
                app = new ThreadExp(null, 0);
             BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
             String line;
             while (true) {
                line = in.readLine();
                line.trim();
                line.toLowerCase();
                if (line.length() == 0) {
                   Thread[] threads = new Thread[Thread.activeCount()];
                   int len = Thread.enumerate(threads);
                   System.out.println("Threads:");
                   for (int index = 0; index < len; index++) {
                      System.out.println("  [" + index + "] " + threads[index].getName());
                } else if (line.equals("stop")) {
                   app.stop();
                } else if (line.equals("quit")) break;
          } catch (Exception e) {
             e.printStackTrace();
          if (app != null) app.stop();
    }---------------------------

    (sigh) Apparently I didn't check the "Java Bug Database" box when I did my search for "+SocketChannel +interrupt". Still, not only does this problem not come up in the Forums, but this current topic doesn't come up either. Very strange.
    This problem may be related to bugs #4470470 and/or #4460583. Both were automatically reported by regression suites almost a year ago before most of the 1.4 betas. The report displayed is cryptic and non-specific. The first would seem to relate to a Win32 thread blocked in a SocketChannel.read() not interrupting when another thread closes the socket. The second seems to be a Linux thread blocked on an unspecified SocketChannel call not interrupting when another thread calls interrupt() on the first thread. The evaluations (both dated Oct 2001) on the first talk about Win32 specific behavior when closing a blocked handle, and the second recommends implementing signal based I/O interruption which is supposed to be the reason NIO was written in the first place.
    Is there any way to gain access to these repression tests so that we might better understand what these automated bug reports really mean? It would help a lot in finding if a problem is actually related to that report or not.
    It strikes me as fundamentally strange that these problems should exist and have existed for so long. Signal sensitive blocking/non-blocking sockets have been used for decades and I've got code for all of this in C/C++. Is there any way to find out what the status is on the implementation of the NIO package? The Java Community Process seems to be of no help since they only deal with specifications and not implementations.
    The scalability bug you mentioned is due to a well-known (at least in Win32 circles) limitation of a function that isn't supposed to be used with sockets in the first place. I'm quite confused by this, but without access to that implementation I cannot analyse the algorithm or suggest/submit native code changes. Is there any way to do this?
    I've cobbled a workaround to my problem. It's ugly, not bullet-proof, and context sensitive, but it works for now. Since this is a client application with specific knowledge of the communication protocol traveling through the channel, the interrupt() call in the stop() method can be replaced with a write() call to the channel that will result in the remote host sending a response. The response will unblock the read() call allowing the thread to detect that it has been terminated (Yeee - uck!).
    Demonstration code JDK1.4.0
    ---------------------------import java.io.*;
    import java.nio.*;
    import java.nio.channels.*;
    import java.nio.charset.*;
    import java.net.*;
    public
    class ThreadExp
    implements Runnable {
       public volatile Thread thread = null;
       String hostname;
       int    port;
       public SocketChannel  channel = null;
       Charset        charset = Charset.forName("US-ASCII");
       CharsetEncoder encoder = charset.newEncoder();
       public
       ThreadExp(String hostname, int port)
          this.hostname = hostname;
          this.port     = port;
          thread = new Thread(this, "ThreadExpThread");
          thread.start();
       public
       void
       stop()
          if (thread == null) return;
          thread = null;
          System.out.println("Stopping thread...");
          try {
             channel.write(encoder.encode(CharBuffer.wrap("\n")));
          } catch (Exception e) {
             e.printStackTrace();
       public
       void
       run()
          CharsetDecoder decoder = charset.newDecoder();
          ByteBuffer     buf     = ByteBuffer.allocateDirect(1024);
          try {
             if (hostname != null) {
                System.out.println("Opening channel...");
                channel = SocketChannel.open(
                   new InetSocketAddress(InetAddress.getByName(hostname), port)
             Thread thisThread = Thread.currentThread();
             while (thread == thisThread) {
                if (hostname != null) {
                   buf.clear();
                   System.out.println("Reading...");
                   int len = channel.read(buf);
                   System.out.println("Read " + len);
                   if (len < 0 || thread != thisThread) break;
                   buf.flip();
                   System.out.print(decoder.decode(buf));
                } else {
                   System.out.println("  .");
                   thread.sleep(1000);
          } catch (InterruptedException e) {
             System.out.println("Thread interupted.");
          } catch (IOException e) {
             e.printStackTrace();
          } finally {
             if (channel != null) {
                try {
                   System.out.println("Closing channel...");
                   channel.close();
                   channel = null;
                } catch (IOException e) {
                   e.printStackTrace();
          System.out.println("Exiting thread.");
       public static
       void
       main(String args[])
          System.out.println(
               "(return)  Display threads\n"
             + "stop      Stop the spun thread\n"
             + "quit      Quit this app and stop any active thread"
          ThreadExp app = null;
          try {
             if (args.length == 2) {
                app = new ThreadExp(args[0], Integer.parseInt(args[1]));
             } else {
                app = new ThreadExp(null, 0);
             BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
             String line;
             while (true) {
                line = in.readLine();
                line.trim();
                line.toLowerCase();
                if (line.length() == 0) {
                   Thread[] threads = new Thread[Thread.activeCount()];
                   int len = Thread.enumerate(threads);
                   System.out.println("Threads:");
                   for (int index = 0; index < len; index++) {
                      System.out.println("  [" + index + "] " + threads[index].getName());
                } else if (line.equals("stop") && app != null) {
                   app.stop();
                   app = null;
                } else if (line.equals("quit")) break;
          } catch (Exception e) {
             e.printStackTrace();
          if (app != null) app.stop();

  • Troubles with timeout using java.nio.channels and non-blocking sockets

    Hello.
    I have a server application that employs java.nio.channels with non-blocking sockets.
    The server waits for connections. The client should connect and be first in sending data.
    Timeouts are significant! If client exceeds the allowed time to send data, the server should break the connection.
    The huge trouble I've discovered that I cannot control the timeout when client connects but remains silent.
    My code looks as follows:
    <pre>
    Selector oSel;
    SocketChannel oSockChan;
    Socket oSock;
    SelectionKey oSelKey;
    Iterator<SelectionKey> oItSelKeys;
    int iCurrState, iMask, iCount;
    iCurrState = INT_SERVER_WORKING;
    iMask = SelectionKey.OP_ACCEPT | SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE;
    while ( iCurrState == INT_SERVER_WORKING )
    try
    *// retrieving next action*
    iCount = oSel.select();
    if ( iCount > 0 )
    oItSelKeys = oSel.selectedKeys().iterator();
    while ( oItSelKeys.hasNext() )
    oSelKey = oItSelKeys.next();
    oItSelKeys.remove();
    if ( oSelKey.isValid() )
    switch ( oSelKey.readyOps() & iMask ) {
    case SelectionKey.OP_ACCEPT :
    oSockChan = oSSockChan.accept();
    oSockChan.configureBlocking(false);
    oSock = oSockChan.socket();
    oSock.setKeepAlive(true);
    oSockChan.register(oSel,SelectionKey.OP_READ,new MyPacket(oSock.getInetAddress(),oSock.getPort()));
    break;
    case SelectionKey.OP_READ :
    oSelKey.interestOps(0);
    ((MyPacket) oSelKey.attachment()).inRequest(); *// preparing request*
    this.getReader().add(oSelKey); *// sending key to reading thread*
    break;
    case SelectionKey.OP_WRITE :
    oSelKey.interestOps(0);
    ((MyRequest) oSelKey.attachment()).inResponse(); *// preparing response*
    this.getWriter().add(oSelKey); *// sending key to writing thread*
    break;
    case SelectionKey.OP_CONNECT :
    default :
    *// nothing to do*
    catch ( IOException oExcept )
    *// do some actions*
    </pre>
    Timeouts are easily controlled by reading and writing threads (see OP_READ and OP_WRITE ).
    But when a client just connects without consequent data send, the state of this connection remains as OP_ACCEPT. The connection remains open for arbitrarily large time and I cannot control it!
    Please help with idea how can I terminate such connections!

    How can I process the keys that weren't selected at the bottom of the loop? Should I use the method keys() ?Yes. Form a new set from keys() and removeAll(selectedKeys()). Do that before you process selectedKeys().
    And the second moment: as I understood a single key may contain several operations simultaneously? Thus I should use several if's (but not if/else 'cause it's the equivalent of switch ... case ).If there is anything unclear about 'your switch statement is invalid. You need an if/else chain' I fail to see what it is. Try reading it again. And if several ifs were really the equivalent of "switch ... case", there wouldn't be a problem in the first place. They're not, and there is.

  • JDK 1.4 nio non-blocking connects don't finish

    I am working with the Linux version of JDK1.4, doing some testing of the
    non-blocking capability. The few tests that I have done have shown some
    strange results:
    - When opening a non-blocking connection to a server which has an
    announcement banner, say such as POP which gives something like:
    +OK pop3 server ready
    then connection seems to be OK and proceed through to completion.
    - When opening a non-blocking connection to a server which is silent, and
    expects me to start the conversation, such as contacting an HTTP server,
    then the Selector.select() never returns to allow me to finish the
    connection.
    Below is a test program which illustrates the problem for me.
    It attempts to open a non-blocking connection to www.yahoo.com on port 80.
    It then drops into a Selector.select() where I am waiting for the chance to
    catch the SelectionKey.OP_CONNECT event and finish connecting, and then send
    a simple HTTP GET request down the wire. That OP_CONNECT event
    never seems to arrive though, and I remain stuck in the select().
    'netstat -na' shows that I am in a connection established state.
    Any insight appreciated,
    -Steve M [email protected]
    ------------------>8 cut here 8<-----------------------
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import java.nio.*;
    import java.nio.channels.*;
    public class NoWorkee
    public static String GET_REQUEST = "GET / HTTP/1.0\r\n\r\n";
        static class Context
            String host;
            int    port;
            ByteBuffer request;
            public Context (String h, int p, ByteBuffer r)
            {host=h; port=p; request=r;}
    Selector sel = null;
    boolean keepGoing = true;
    public NoWorkee()
        throws IOException
        sel = Selector.open();
    public void add(String host, int port)
        throws IOException
        int ops = SelectionKey.OP_CONNECT;
        // create non-blocking socket, and initiate connect operation
        SocketChannel sc = SocketChannel.open();
        sc.configureBlocking(false);
        sc.connect(new InetSocketAddress(InetAddress.getByName(host), port));
        SelectionKey sk;
        try
            sk = sc.register(sel, ops);
            System.out.println ( "sc.register looks good connected=" +
                sc.isConnected() + ", isConnectionPending=" +
                sc.isConnectionPending());
            sk.attach(new Context(host, port, ByteBuffer.wrap(GET_REQUEST.getBytes())));
        catch (IOException x)
            x.printStackTrace();
            sc.close();
    public void run()
        throws IOException
        keepGoing = true;
        System.out.println ( "Selecting " + sel.keys().size() + " SelectKeys");
        while (keepGoing)
            final long before = System.currentTimeMillis();
            final int numReady = sel.select();
            //final int numReady = sel.select(1000);
            final long after = System.currentTimeMillis();
            System.out.println ( "Blocked " + (after-before) + " ms, numReady=" + numReady);
            if (numReady > 0)
                Set readyKeys = sel.selectedKeys();
                System.out.println ( "Selected keys size " + readyKeys.size());
                for (Iterator it = readyKeys.iterator(); it.hasNext();)
                    SelectionKey sk = (SelectionKey)it.next();
                    SocketChannel sockChan = (SocketChannel)sk.channel();
                    Context ctx = (Context)sk.attachment();
                    System.out.println ( "Servicing host " + ctx.host + " port "
                                 ctx.port);
    System.out.println ( "1");
                    if (sk.isConnectable())
                        if (sockChan.finishConnect())
                            System.out.println ( "Finished connecting success "
    + sockChan);
                            int ops = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
                            sk.interestOps (ops);
                        else
                            System.out.println ( "Could not finishConnect for "
                                sockChan);
                            sk.cancel();
                            sockChan.close();
    System.out.println ( "2");
                    if (sk.isAcceptable())
                        System.out.println ( "in sk.isAcceptable() block");
    System.out.println ( "3");
                    if (sk.isReadable())
                        System.out.println ( "in sk.isReadable() block");
                        byte rawBuff[] = new byte[32 * 1024];
                        ByteBuffer buff = ByteBuffer.wrap(rawBuff);
                        int numRead = -1;
                        while (0 < (numRead = sockChan.read(buff)))
                            System.out.println ( "numRead = " + numRead);
                            for (int i = 0; i < numRead; i++)
                                System.out.print((char)rawBuff);
    System.out.println ( "numRead = " + numRead);
    System.out.println ( "4");
    if (sk.isWritable())
    System.out.println ( "in sk.isReadable() block");
    int numWritten = -1;
    if (null != ctx.request)
    numWritten = sockChan.write(ctx.request);
    if (!ctx.request.hasRemaining())
    sk.interestOps(sk.interestOps() &
    ~SelectionKey.OP_WRITE);
    System.out.println ( "numWritten = " + numWritten);
    //else
    // service timeouts
    public static void main (String arg[])
    try
    NoWorkee bla = new NoWorkee();
    bla.add ("www.yahoo.com", 80);
    bla.run();
    catch (Exception e)
    e.printStackTrace();
    ------------------>8 cut here 8<-----------------------

    Just for the benefit of anyone who might be seeing the same problem, it looks like bug 4457776 accurately describes the problem that I was having above.
    I am downloading j2sdk-1_4_0-beta2-linux-i386-rpm.bin to see if that fixed it.
    Reference:
    http://developer.java.sun.com/developer/bugParade/bugs/4457776.html

  • Are the experts wrong about non-blocking SocketChannels?

    Everyone says to use the new SocketChannel and Selector for "highly scalable" server applications. So I ran a couple of tests using non-blocking (via Selector) and thread-per-connection SocketChannels.
    The Selector version consumes 8x more cpu than the thread-per-connecton version!
    Using JDK 1.4.1 FCS on Win2K, with 1000 socket connections each sending 1k bytes per second, the Selector version was consuming 40% cpu with 10 threads; the thread-per-connection version (using blocking SocketChannels) was only consuming about 5% cpu with 1009 threads.
    So, are the experts wrong? Is there a performance problem when number of SocketChannels exceed a certain threshold?
    For anyone interested, here's the source code:
    Non-Blocking Server using Selector
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.nio.charset.CharsetEncoder;
    import java.nio.channels.FileChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Set;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    public class Server4 implements Runnable
    private static int port = 80;
    public static void main(String args[]) throws Exception
    Server4 server = new Server4();
    Thread thread = new Thread(server);
    thread.setDaemon(true);
    thread.start();
    thread.join();
    public Server4() throws IOException
    ServerSocketChannel server = ServerSocketChannel.open();
    InetSocketAddress isa = new InetSocketAddress(port);
    server.configureBlocking(false);
    server.socket().bind(isa);
    m_selector = Selector.open();
    server.register(m_selector, SelectionKey.OP_ACCEPT);
    Charset utf8 = Charset.forName("UTF-8");
    m_decoder = utf8.newDecoder();
    m_encoder = utf8.newEncoder();
    public void run()
    int count = 0;
    try
    ByteBuffer buffer = ByteBuffer.allocateDirect(2048);
    //FileOutputStream fos = new FileOutputStream("server4.dat");
    //FileChannel fc = fos.getChannel();
    while (m_selector.select() > 0)
    Set keys = m_selector.selectedKeys();
    for (Iterator itr = keys.iterator(); itr.hasNext(); )
    SelectionKey key = (SelectionKey) itr.next();
    itr.remove();
    if (key.isAcceptable())
    System.out.println("accept: " + (++count));
    ServerSocketChannel server
    = (ServerSocketChannel) key.channel();
    SocketChannel channel = server.accept();
    channel.configureBlocking(false);
    channel.register(m_selector, SelectionKey.OP_READ);
    else
    SocketChannel channel = null;
    try
    if (key.isReadable())
    channel = (SocketChannel) key.channel();
    int bytes = channel.read(buffer);
    if (bytes <= 0) // Linux does not throw IOException
    channel.close(); // will also cancel key
    System.out.println("connection closed " + count);
    else
    buffer.flip();
    //fc.write(buffer);
    buffer.clear();
    catch (IOException ioe) // connection closed by client
    System.out.println("readable: " + ioe.getMessage());
    sm_logger.log(Level.INFO, ioe.getMessage(), ioe);
    Throwable cause = ioe.getCause();
    if (cause != null)
    System.out.println("cause: "
    + cause.getClass().getName()
    + ": " + cause.getMessage());
    channel.close(); // will also cancel key
    --count;
    catch (IOException e)
    System.out.println("run: " + e.getMessage());
    sm_logger.log(Level.SEVERE, e.getMessage(), e);
    catch (Exception e)
    System.out.println("run: " + e.getMessage());
    sm_logger.log(Level.SEVERE, e.getMessage(), e);
    private Selector m_selector;
    private CharsetDecoder m_decoder;
    private CharsetEncoder m_encoder;
    private static Logger sm_logger = Logger.getLogger("Server");
    Thread-Per-Connection Server
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.nio.charset.CharsetEncoder;
    import java.nio.channels.FileChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Set;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    public class MultiThreadServer implements Runnable
    private static int port = 80;
    public static void main(String[] args) throws Exception
    ServerSocketChannel server = ServerSocketChannel.open();
    InetSocketAddress isa = new InetSocketAddress(port);
    server.socket().bind(isa);
    int count = 0;
    while (true)
    SocketChannel channel = server.accept();
    System.out.println("accept: " + (++count));
    MultiThreadServer worker = new MultiThreadServer(channel);
    Thread thread = new Thread(worker);
    thread.setDaemon(true);
    thread.start();
    public MultiThreadServer(SocketChannel channel) throws IOException
    m_channel = channel;
    public void run()
    ByteBuffer buffer = ByteBuffer.allocateDirect(2048);
    int bytes = 0;
    try
    while ((bytes = m_channel.read(buffer)) > 0)
    buffer.flip();
    // process buffer
    buffer.clear();
    System.out.println("connection closed");
    m_channel.close();
    catch (IOException e)
    System.out.println("run: " + e.getMessage());
    sm_logger.log(Level.SEVERE, e.getMessage(), e);
    catch (Exception e)
    System.out.println("run: " + e.getMessage());
    sm_logger.log(Level.SEVERE, e.getMessage(), e);
    private SocketChannel m_channel;
    private static Logger sm_logger = Logger.getLogger("MultiThreadServer");
    Client
    import java.io.*;
    import java.net.*;
    import java.nio.*;
    import java.nio.channels.*;
    import java.nio.charset.*;
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    public class MultiClient implements Runnable
    public static void main(String[] args) throws Exception
    if (args.length < 1)
    System.out.println("usage: java MultiClient number [host]");
    System.exit(1);
    int number = Integer.parseInt(args[0]);
    String host = (args.length == 2) ? args[1] : "localhost" ;
    Thread[] threads = new Thread [number];
    InetSocketAddress address = new InetSocketAddress(host, 80);
    for (int i = 0; i < number; i++)
    MultiClient client = new MultiClient(address, Integer.toString(i));
    threads[i] = new Thread(client);
    threads.setDaemon(true);
    for (int i = 0; i < number; i++)
    threads[i].start();
    for (int i = 0; i < number; i++)
    threads[i].join();
    public MultiClient(InetSocketAddress address, String id)
    throws InterruptedException, IOException
    m_id = id;
    Charset charset = Charset.forName("UTF-8");
    m_decoder = charset.newDecoder();
    m_encoder = charset.newEncoder();
    m_channel = SocketChannel.open();
    m_channel.connect(address);
    if (id.equals("0"))
    Socket socket = m_channel.socket();
    System.out.println("SO_SNDBUF=" + socket.getSendBufferSize()
    + ",SO_TIMEOUT=" + socket.getSoTimeout()
    + ",SO_KEEPALIVE=" + socket.getKeepAlive());
    byte[] buf = new byte [1024]; // bufsize = 1K
    Arrays.fill(buf, (byte) m_id.charAt(0));
    m_buffer = ByteBuffer.allocateDirect(1024);
    m_buffer.put(buf);
    m_buffer.flip();
    Thread.currentThread().sleep(50L);
    public void run()
    System.out.print(m_id);
    try
    while (true)
    m_channel.write(m_buffer);
    m_buffer.rewind();
    Thread.currentThread().sleep(1000L);
    catch (IOException ioe)
    ioe.printStackTrace();
    catch (InterruptedException ie)
    System.err.println(ie.toString());
    private String m_id;
    private CharsetEncoder m_encoder;
    private CharsetDecoder m_decoder;
    private SocketChannel m_channel;
    private ByteBuffer m_buffer;

    {This is a crosspost. I posted this earlier today at http://forum.java.sun.com/thread.jsp?forum=4&thread=319822 before I stumbled on a search phrase that located this older thread.
    All follow-ups should be on haam's thread instead of mine. The important point below is that NIO select() behavior (vs. threading IO)  is [b]worse under Windows but better under Solaris. This seems fundamentally broken. }
    My company sells a scalable multi-user server platform built on Java 2.
    It runs under Java 1.3.1 (and 1.4.0 windows) using multiple threads for communications, and 1.4.x (unix) using NIO. We were happy to see that 1.4.1 (windows) fixed the problem drastically limiting the number of selectable ports. :-)
    The bad news is that whatever the VM is doing "under the sheets" to fix the problem seems to perform very poorly in terms of CPU:
    I compared connecting 500 simulated users to a Solaris 8 and a Win2K box. These users were in 25 chat rooms, each sending a chat message every 30 seconds. (There was plenty of memory on each machine. There was no swapping in either case. Clock/CPU type doesn't matter as this isn't about comparing a machine to a machine, but different load characteristics -within- a machine environment.)
                    Threaded IO      NIO/Select
    Solaris 1.4.1     20-30%           15- 20%
    Windows 1.4.1     40-50%           95-100%Numbers are % of CPU as reported by 'top' and the Win2K task manager.
    Both platforms showed the expected significant improvement in memory usage when moving from standard threaded IO to NIO.
    Strangely, the Windows implementation of the VM showed a significant (and unexpected) degradation of NIO performance vs. the threaded model, whereas the Solaris VM behaved as expected: NIO outperformed threaded IO.
    Our best guess is that the Selector fix in 1.4.1 is implemented in some cpu-intensive way; perhaps polling. As a result, we still can't use NIO for Wintel boxes running our server. :-( To us, Selector
    is still broken.
    Has anyone else seen results like this? Have we missed some configuration parameter that will fix this?
    I thought the big upside of using select() was supposed to be performance. :-P
    F. Randall Farmer
    State Software, Inc.
    http://www.statesoftware.com

  • Non-blocking SocketChannels

    I'm trying to learn how to use non-blocking socket channles, but I haven't found much info (nor luck) so far.
    To learn, I'm building a server and a client. The server accepts input from the clients and process it in only one thread. The clients should send Objects to the server, and the server process them and return the result also as an Object. For this, I'm trying to use ObjectOutputStream and ObjectInputStream.
    The problem I don't know how to solve is that the SocketChannel is in non-bolcking mode, so I can't use their input/output streams (I get a IllegalBlockingModeException). In the server process loop I can reconfigure the SocketChannel to blocking mode to be able to read the Object, but I can't configure it to non-blocking mode again because I get a CancelledKeyException.
    Does anyone know how to work with InputStreams and non-blocking channels? Or where to find more info about it?
    Here are the relevant part of the server code:
    Set ready = selector.selectedKeys();
    Iterator i = ready.iterator();
    while (i.hasNext()) {
       try {
          SelectionKey sk = i.next();
          i.remove();
          if (sk.isAcceptable()) {
             ServerSocketChannel ssc = (ServerSocketChannel)sk.channel();
             SocketChannel sc = ssc.accept();
             sc.configureBlocking(false);
             sc.register(selector, SelectionKey.OP_READ);
          } else if (sk.isReadable()) {
             SocketChannel sc = (SocketChannel)sk.channel();
             // PROBLEM: If the channel is in non-blocking mode
             // I cannot use InputStreams
             sk.cancel();
             sc.configureBlocking(true);
             // Read the object sent by the client
             ObjectInputStream in = new ObjectInputStream(Channels.newInputStream(sc));
             Object o = in.readObject();
             // PROBLEM: Can't put the channel back to non-blocking mode
             sc.configureBlocking(false);
             sc.register(selector, SelectionKey.OP_READ); // CancelledKeyException
       } catch (...){
    }

    In my client, this is working fine:
    ObjectOutputStream oos = null;
    ObjectInputStream ois = null;
    for (int i = 0; i < 30000; i++) {
       oos = new ObjectOutputStream(sc.socket().getOutputStream());
       oos.writeObject(object);
       oos.flush();
       ois = new ObjectInputStream(sc.socket().getInputStream());
       Object o = ois.readObject();
    }But trying to do it like this throws a StreamCorruptedException at the server side.
    ObjectOutputStream oos = new ObjectOutputStream(sc.socket().getOutputStream());
    ObjectInputStream ois = new ObjectInputStream(sc.socket().getInputStream());
    for (int i = 0; i < 30000; i++) {
       oos.writeObject(object);
       oos.flush();
       Object o = ois.readObject();
    }Do you know why?

  • Non-blocking connection on a SocketChannel?

    I'm trying out the non-blocking connection of a SocketChannel. So I wrote the following test code and supply a list of IPs (both good and bad IPs). But disregard the IPs I always get the result of a channel being in connection pending state (even for some bogus IPs). Any help will be great.
    public class ConnectTest
        public static void main(String[] args) throws
    Exception
            List<SocketChannel> channels = new ArrayList<SocketChannel>();
            for ( String s: args )
                SocketChannel channel = SocketChannel.open();
                channel.configureBlocking(false);
                channels.add(channel);        
                InetSocketAddress remote = new InetSocketAddress(s, 80);
                channel.connect(remote);
            System.out.println("wait for timeout...");
            Thread.sleep(10000);
            for ( SocketChannel c : channels )
                if ( c.isConnected() )
                    System.out.println(c.socket().getInetAddress() + " connected ");
                else if ( c.isConnectionPending() )
                    System.out.println(c.socket().getInetAddress() + " connection pending ");               
                else
                    System.out.println(c.socket().getInetAddress() + " timeout ");
                c.close();
    }

    Forget the sleep: use a Selector, selecting on OP_CONNECT. When you get it, call SocketChannel.finishConnect() for the channel(s) selected. If that method returns 'true', the connection is complete. If it returns 'false', the connection is still pending (and in fact OP_CONNECT should not have fired); if it throws an exception, the connection attempt has failed.
    If the connection is complete you must also deregister it for OP_CONNECT before registering it for OP_READ or OP_WRITE.

Maybe you are looking for