Java nio server always stuck on selector.select

I'm trying to write a simple client server model using NIO (to learn how it works). There are 2 types of messages that can be sent Connection (which is a message the server sends to a client when it connects giving it info like its client id) and Ping.

If a client has not been pinged for a time period of > 4 seconds the server will ping the client and the client will respond with a pong.

When I initialize my server I do it like so:

    try{
        selector = Selector.open();
        selector.wakeup();
        serverChannel = selector.provider().openServerSocketChannel();
        serverChannel.socket().bind(new InetSocketAddress(port));
        serverChannel.configureBlocking(false);

        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }catch (IOException e){
        log.Error(e);
        throw new RuntimeException("Error opening selector.", e);
    }

after this happens we enter our server loop which will find what keys have been selected and performed the selected operation on the keys

int select = 0;

    while (running){ 
        try{
           select = selector.select(timeout);

           if(select == 0){
               continue;
           }
           Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();

           while(selectedKeys.hasNext()){
               SelectionKey key = selectedKeys.next();
               selectedKeys.remove();

               Connection conn = (Connection)key.attachment();

               if(conn != null){
                   if(key.isValid() && key.isReadable()){
                                  //handle key reads
                   }
                   if(key.isValid() && key.isWritable()){
                          //handle key writes
                   }

                   continue;
               }

               if(key.isValid() && key.isAcceptable()){
                   Connection newConn = new Connection(transport, packetFactory, nextConnectionId);

                   try{
                       SelectionKey selectionKey = newConn.getConnection().handleAccept(selector, serverChannel.accept());
                       selectionKey.attach(newConn);

                            //send the client a connection message

                       nextConnectionId++;
                   }catch(IOException e){
                       newConn.close();
                       log.Error(e);
                   }
               }
           }

           long time = System.nanoTime();
           for(Connection c : connections){
               if(c.getConnection().isTimedOut(time)){
                   c.close();
                }

                if(c.needsPing(time)) {
                    c.sendPing();
                }
           }
        }catch(IOException e){
            log.Error(e);
        }
    }

the handleAccept() method looks like so

public SelectionKey handleAccept(Selector selector, SocketChannel ch) {

    try{
        socketChannel = ch;
        socketChannel.configureBlocking(false);
        lastReadTime = System.nanoTime();
        selectionKey = ch.register(selector, SelectionKey.OP_READ);

        return selectionKey;
    }catch(IOException e){
        close();
    }
}

the handleAccept() method is part of the connection object which holds information such as the connections socketChannel, selectionkey. Whenever the connection is read/write these are updated like so:

public void handleWrite(SelectionKey key) throws IOException {
    socketChannel = (SocketChannel) key.channel();
    this.selectionKey = key;

    //do other stuff
 }

finally when we need to write something to the client we tell the socketChannel that we're interested in writing and once we finish writing we tell it we want to read. This is done by accessing the connections selection key and setting its interestOps() to the correct field.

When I run this code the server does the following:

[2014/05/25 01:49:23] [INFO] [com.adammflax.net.ServerEndPoint] Started Server on port 9001
[2014/05/25 01:49:26] [INFO] [com.adammflax.net.ServerEndPoint] Added the connection com.adammflax.net.Connection@4838ddcc to the list of connections on the server
[2014/05/25 01:49:26] [INFO] [com.adammflax.net.ServerEndPoint] Client com.adammflax.net.Connection@4838ddcc connected to the server given a Id of 0
30
[CLIENT RECEIVES CONNECTION PACKET]
[2014/05/25 01:49:26] [DEBUG] [com.adammflax.net.ServerEndPoint] Received ping from client now replying
[CLIENT RECEIVES Ping PACKET]

after this however the server just gets stuck on selector.select() (it will always timeout and return 0). Can anyone explain to me why this is happening. I know this is a lot of code to dig through (and bits are missing to try and condense this) but any help on the matter would be amazing.

edit adding more code to show how we detect if a ping needs to happen (which belongs to the connection object)

public boolean needsPing(long time) {
    if(!isConnected()){
        return false;
    }

    if(pingTime <= 0){
        return false;
    }

    if(time <= lastPingSentTime + pingTime){
        return false;
    }

    lastPingSentTime = System.nanoTime();

    return true;
}

send ping turns a pingPacket object into bytes and calls the send Method which adds the bytes to a messageQueue called messages.

public void send(byte[] message) {
    messages.add(message);
    selectionKey.interestOps(SelectionKey.OP_WRITE);
}

as we are now in OP_WRITE handleWrite will eventually be called

public void handleWrite(SelectionKey key) throws IOException {
    socketChannel = (SocketChannel) key.channel();

    if(socketChannel == null){
        key.cancel();
        throw new SocketException("Socket connection has closed!");
    }

    while(!messages.isEmpty()){
        try{
            writeBuffer = ByteBuffer.wrap(messages.peek());


            if(socketChannel.write(writeBuffer) == 0){
                break;
            }

            if (writeBuffer.remaining() > 0) {
                break;
            }

            writeBuffer.compact();
            messages.poll(); //everything went well so remove head
        }catch(IOException e){
            log.Error("failed to write : " + messages.peek() + " at " +
                    this.socketChannel.getRemoteAddress());
        }
    }   

    selectionKey.interestOps(SelectionKey.OP_READ);
}
链接地址: http://www.djcxy.com/p/34130.html

上一篇: 有没有办法发送数据作为从nio服务器到io客户端的响应?

下一篇: Java nio服务器总是停留在selector.select上