connectiontablenio.java

来自「JGRoups源码」· Java 代码 · 共 1,494 行 · 第 1/4 页

JAVA
1,494 行
字号
               {                  SelectionKey key = (SelectionKey) i.next();                  i.remove();                  // Do partial read and handle call back                  Connection conn = (Connection) key.attachment();                  try                  {                     if (conn.getSocketChannel().isOpen())                        readOnce(conn);                     else                     {  // socket connection is already closed, clean up connection state                        conn.closed();                     }                  } catch (IOException e)                  {                     if (LOG.isTraceEnabled()) LOG.trace("Read operation on socket failed" , e);                     // The connection must be bad, cancel the key, close socket, then                     // remove it from table!                     key.cancel();                     conn.destroy();                     conn.closed();                  }               }            }            // Now we look at the connection queue to get any new connections added            Object o;            try            {               o = QUEUE.poll(0); // get a connection            } catch (InterruptedException e)            {               if (LOG.isInfoEnabled()) LOG.info("Thread ("+Thread.currentThread().getName() +") was interrupted while polling queue" ,e);               // We must give up               continue;            }            if (null == o)               continue;            if (o instanceof Shutdown) {     // shutdown command?               try {                  SELECTOR.close();               } catch(IOException e) {                  if (LOG.isInfoEnabled()) LOG.info("Read selector close operation failed" , e);               }               return;                       // stop reading            }            Connection conn = (Connection) o;// must be a new connection            SocketChannel sc = conn.getSocketChannel();            try            {               sc.register(SELECTOR, SelectionKey.OP_READ, conn);            } catch (ClosedChannelException e)            {               if (LOG.isInfoEnabled()) LOG.info("Socket channel was closed while we were trying to register it to selector" , e);               // Channel becomes bad. The connection must be bad,               // close socket, then remove it from table!               conn.destroy();               conn.closed();            }         }   // end of the while true loop      }      private void readOnce(Connection conn)         throws IOException      {         ConnectionReadState readState = conn.getReadState();         if (!readState.isHeadFinished())         {  // a brand new message coming or header is not completed            // Begin or continue to read header            int size = readHeader(conn);            if (0 == size)            {  // header is not completed               return;            }         }         // Begin or continue to read body         if (readBody(conn) > 0)         { // not finish yet            return;         }         Address addr = conn.getPeerAddress();         ByteBuffer buf = readState.getReadBodyBuffer();         // Clear status         readState.bodyFinished();         // Assign worker thread to execute call back         try         {            connectTable.runRequest(addr, buf);         } catch (InterruptedException e)         {            // Cannot do call back, what can we do?            // Give up handling the message then            LOG.error("Thread ("+Thread.currentThread().getName() +") was interrupted while assigning executor to process read request" , e);         }      }      /**       * Read message header from channel. It doesn't try to complete. If there is nothing in       * the channel, the method returns immediately.       *       * @param conn The connection       * @return 0 if header hasn't been read completely, otherwise the size of message body       * @throws IOException       */      private int readHeader(Connection conn)         throws IOException      {         ConnectionReadState readState = conn.getReadState();         ByteBuffer headBuf = readState.getReadHeadBuffer();         SocketChannel sc = conn.getSocketChannel();         while (headBuf.remaining() > 0)         {            int num = sc.read(headBuf);            if (-1 == num)            {// EOS               throw new IOException("Peer closed socket");            }            if (0 == num) // no more data               return 0;         }         // OK, now we get the whole header, change the status and return message size         return readState.headFinished();      }      /**       * Read message body from channel. It doesn't try to complete. If there is nothing in       * the channel, the method returns immediately.       *       * @param conn The connection       * @return remaining bytes for the message       * @throws IOException       */      private int readBody(Connection conn)         throws IOException      {         ByteBuffer bodyBuf = conn.getReadState().getReadBodyBuffer();         SocketChannel sc = conn.getSocketChannel();         while (bodyBuf.remaining() > 0)         {            int num = sc.read(bodyBuf);            if (-1 == num) // EOS               throw new IOException("Couldn't read from socket as peer closed the socket");            if (0 == num) // no more data               return bodyBuf.remaining();         }         // OK, we finished reading the whole message! Flip it (not necessary though)         bodyBuf.flip();         return 0;      }   }   private class ExecuteTask implements Runnable {      Address m_addr = null;      ByteBuffer m_buf = null;      public ExecuteTask(Address addr, ByteBuffer buf)      {         m_addr = addr;         m_buf = buf;      }      public void run()      {         receive(m_addr, m_buf.array(), m_buf.arrayOffset(), m_buf.limit());      }   }   private class ConnectionReadState {      private final Connection m_conn;      // Status for receiving message      private boolean m_headFinished = false;      private ByteBuffer m_readBodyBuf = null;      private final ByteBuffer m_readHeadBuf = ByteBuffer.allocate(Connection.HEADER_SIZE);      public ConnectionReadState(Connection conn)      {         m_conn = conn;      }      ByteBuffer getReadBodyBuffer()      {         return m_readBodyBuf;      }      ByteBuffer getReadHeadBuffer()      {         return m_readHeadBuf;      }      void bodyFinished()      {         m_headFinished = false;         m_readHeadBuf.clear();         m_readBodyBuf = null;         m_conn.updateLastAccessed();      }      /**       * Status change for finishing reading the message header (data already in buffer)       *       * @return message size       */      int headFinished()      {         m_headFinished = true;         m_readHeadBuf.flip();         int messageSize = m_readHeadBuf.getInt();         m_readBodyBuf = ByteBuffer.allocate(messageSize);         m_conn.updateLastAccessed();         return messageSize;      }      boolean isHeadFinished()      {         return m_headFinished;      }   }   class Connection extends ConnectionTable.Connection {      private SocketChannel sock_ch = null;      private WriteHandler m_writeHandler;      private SelectorWriteHandler m_selectorWriteHandler;      private final ConnectionReadState m_readState;      private static final int HEADER_SIZE = 4;      final ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE);      Connection(SocketChannel s, Address peer_addr)      {         super(s.socket(), peer_addr);         sock_ch = s;         m_readState = new ConnectionReadState(this);          is_running=true;      }      private ConnectionReadState getReadState()      {         return m_readState;      }      private void setupWriteHandler(WriteHandler hdlr)      {         m_writeHandler = hdlr;         m_selectorWriteHandler = hdlr.add(sock_ch);      }//      void destroy()//      {//         closeSocket();//      }      void doSend(byte[] buffie, int offset, int length) throws Exception      {         FutureResult result = new FutureResult();         m_writeHandler.write(sock_ch, ByteBuffer.wrap(buffie, offset, length), result, m_selectorWriteHandler);         Exception ex = result.getException();         if (ex != null)         {            if (LOG.isErrorEnabled())               LOG.error("failed sending message", ex);            if (ex.getCause() instanceof IOException)               throw (IOException) ex.getCause();            throw ex;         }         result.get();      }      SocketChannel getSocketChannel()      {         return sock_ch;      }      void closeSocket()      {         if (sock_ch != null)         {            try            {               if(sock_ch.isConnected() && sock_ch.isOpen()) {                  sock_ch.close();               }            }            catch (Exception e)            {               log.error("error closing socket connection", e);            }            sock_ch = null;         }      }      void closed()      {         Address peerAddr = getPeerAddress();         synchronized (conns)         {            conns.remove(peerAddr);         }         notifyConnectionClosed(peerAddr);      }   }   /**    * Handle writing to non-blocking NIO connection.    */   private static class WriteHandler implements Runnable {      // Create a queue for write requests      private final LinkedQueue QUEUE = new LinkedQueue();      private final Selector SELECTOR = initSelector();      private int m_pendingChannels;                 // count of the number of channels that have pending writes      // note that this variable is only accessed by one thread.      // allocate and reuse the header for all buffer write operations      private ByteBuffer m_headerBuffer = ByteBuffer.allocate(Connection.HEADER_SIZE);      Selector initSelector() {         try         {            return SelectorProvider.provider().openSelector();         }         catch (IOException e)         {            if (LOG.isErrorEnabled()) LOG.error(e);            throw new IllegalStateException(e.getMessage());         }      }      /**       * create instances of WriteHandler threads for sending data.       *       * @param workerThreads is the number of threads to create.       */      private static WriteHandler[] create(int workerThreads, ThreadGroup tg, LinkedList backGroundThreads)      {         WriteHandler[] handlers = new WriteHandler[workerThreads];         for (int looper = 0; looper < workerThreads; looper++)         {            handlers[looper] = new WriteHandler();            Thread thread = new Thread(tg, handlers[looper], "nioWriteHandlerThread");            thread.setDaemon(true);            thread.start();            backGroundThreads.add(thread);         }         return handlers;      }      /**       * Add a new channel to be handled.       *       * @param channel       */      private SelectorWriteHandler add(SocketChannel channel)      {          return new SelectorWriteHandler(channel, SELECTOR, m_headerBuffer);      }      /**       * Writes buffer to the specified socket connection.  This is always performed asynchronously.  If you want       * to perform a synchrounous write, call notification.`get() which will block until the write operation is complete.       * Best practice is to call notification.getException() which may return any exceptions that occured during the write       * operation.       *       * @param channel      is where the buffer is written to.       * @param buffer       is what we write.       * @param notification may be specified if you want to know how many bytes were written and know if an exception

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?