public void process(SelectionKey key) {
      try {
        ByteBuffer buf = ByteBuffer.allocate(1024);
        int result;
        while (0 < (result = sessionChannel.read(buf))) {
          buf.flip();
          messageReceived(new ByteArrayBuffer(buf.array(), buf.position(), buf.remaining()));
          if (result == 1024) {
            buf.rewind();
          } else {
            return;
          }
        }

        if (result == -1) {
          // EOF => remote closed the connection, cancel the selection key and close the channel.
          key.cancel();
          sessionChannel.close();
        }
      } catch (IOException e) {
        LOGGER.log(Level.INFO, "Could not write response to socket", e);
        key.cancel();
        safelyClose(sessionChannel);
      }
    }
Esempio n. 2
0
 @Override
 public void run() {
   final Selector selector = this.selector;
   for (; ; ) {
     ++reactCount;
     try {
       selector.select(1000L);
       register(selector);
       Set<SelectionKey> keys = selector.selectedKeys();
       try {
         for (SelectionKey key : keys) {
           Object att = key.attachment();
           System.out.println("attchment " + att);
           if (att != null && key.isValid()) {
             int readyOps = key.readyOps();
             if ((readyOps & SelectionKey.OP_READ) != 0) {
               read((NIOConnection) att);
             } else if ((readyOps & SelectionKey.OP_WRITE) != 0) {
               write((NIOConnection) att);
             } else {
               key.cancel();
             }
           } else {
             key.cancel();
           }
         }
       } finally {
         keys.clear();
       }
     } catch (Throwable e) {
       LOGGER.warn(name, e);
     }
   }
 }
Esempio n. 3
0
  private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Clear out our read buffer so it's ready for new data
    this.readBuffer.clear();

    // Attempt to read off the channel
    int numRead;
    try {
      numRead = socketChannel.read(this.readBuffer);
    } catch (IOException e) {
      // The remote forcibly closed the connection, cancel
      // the selection key and close the channel.
      key.cancel();
      socketChannel.close();
      return;
    }

    if (numRead == -1) {
      // Remote entity shut the socket down cleanly. Do the
      // same from our end and cancel the channel.
      key.channel().close();
      key.cancel();
      return;
    }

    // Hand the data off to our worker thread
    this.worker.processData(this, socketChannel, this.readBuffer.array(), numRead);
  }
Esempio n. 4
0
  private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Clear out our read buffer so it's ready for new data
    readBuffer.clear();

    // Attempt to read off the channel
    int numRead;
    try {
      numRead = socketChannel.read(readBuffer);
    } catch (IOException e) {
      key.cancel();
      socketChannel.close();

      System.out.println("Forceful shutdown");
      return;
    }

    if (numRead == -1) {
      System.out.println("Graceful shutdown");
      key.channel().close();
      key.cancel();

      return;
    }

    socketChannel.register(selector, SelectionKey.OP_WRITE);

    numMessages++;
    if (numMessages % 100000 == 0) {
      long elapsed = System.currentTimeMillis() - loopTime;
      loopTime = System.currentTimeMillis();
      System.out.println(elapsed);
    }
  }
Esempio n. 5
0
  /** Handle a read event from a socket specified by the key. */
  private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();
    SocketAddress remoteAdr = socketChannel.socket().getRemoteSocketAddress();

    // Clear out our read buffer so it's ready for new data
    readBuffer.clear();

    // Attempt to read off the channel
    int numRead;
    try {
      numRead = socketChannel.read(readBuffer);
    } catch (IOException e) {
      // The remote forcibly closed the connection, cancel
      // the selection key and close the channel.
      key.cancel();
      socketChannel.close();
      clients.remove(remoteAdr);
      pendingWriteData.remove(socketChannel);
      logger.fine(
          "Connection forcibly closed("
              + remoteAdr
              + ")! Remaining connections: "
              + clients.size());
      throw new IOException("Remote forcibly closed the connection");
    }

    if (numRead == -1) {
      // Remote entity shut the socket down cleanly. Do the
      // same from our end and cancel the channel.
      key.channel().close();
      key.cancel();
      clients.remove(remoteAdr);
      pendingWriteData.remove(socketChannel);
      logger.fine("Connection Closed(" + remoteAdr + ")! Remaining connections: " + clients.size());
      throw new IOException("Remote closed the connection");
    }

    // Make a correctly sized copy of the data before handing it to the client
    // byte[] rspByteData = new byte[numRead];
    // System.arraycopy(readBuffer.array(), 0, rspByteData, 0, numRead);

    try {
      Object rspData = Converter.toObject(readBuffer.array());

      // Hand the data off to our worker thread
      if (worker != null) {
        logger.finer("Handling incoming message...");
        worker.processData(this, socketChannel.getRemoteAddress(), rspData);
      } else {
        logger.fine("No worker set, message unhandled!");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
Esempio n. 6
0
  private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    DataServerMessage tMessage;
    if (mReceivingData.containsKey(socketChannel)) {
      tMessage = mReceivingData.get(socketChannel);
    } else {
      tMessage = DataServerMessage.createBlockRequestMessage();
      mReceivingData.put(socketChannel, tMessage);
    }

    // Attempt to read off the channel
    int numRead;
    try {
      numRead = tMessage.recv(socketChannel);
    } catch (IOException e) {
      // The remote forcibly closed the connection, cancel the selection key and close the channel.
      key.cancel();
      socketChannel.close();
      mReceivingData.remove(socketChannel);
      mSendingData.remove(socketChannel);
      return;
    }

    if (numRead == -1) {
      // Remote entity shut the socket down cleanly. Do the same from our end and cancel the
      // channel.
      key.channel().close();
      key.cancel();
      mReceivingData.remove(socketChannel);
      mSendingData.remove(socketChannel);
      return;
    }

    if (tMessage.isMessageReady()) {
      if (tMessage.getBlockId() <= 0) {
        LOG.error("Invalid block id " + tMessage.getBlockId());
        return;
      }

      key.interestOps(SelectionKey.OP_WRITE);
      LOG.info("Get request for " + tMessage.getBlockId());
      int lockId = mBlocksLocker.lock(tMessage.getBlockId());
      DataServerMessage tResponseMessage =
          DataServerMessage.createBlockResponseMessage(
              true, tMessage.getBlockId(), tMessage.getOffset(), tMessage.getLength());
      tResponseMessage.setLockId(lockId);
      mSendingData.put(socketChannel, tResponseMessage);
    }
  }
 private void connect(SelectionKey k) {
   NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment();
   try {
     if (ch.channel.finishConnect()) {
       k.cancel();
       ch.worker.register(ch, ch.connectFuture);
     }
   } catch (Throwable t) {
     ch.connectFuture.setFailure(t);
     fireExceptionCaught(ch, t);
     k.cancel(); // Some JDK implementations run into an infinite loop without this.
     ch.worker.close(ch, succeededFuture(ch));
   }
 }
Esempio n. 8
0
  private void close(SelectionKey key) {
    try {
      RapidoidConnection conn = (RapidoidConnection) key.attachment();

      if (key.isValid()) {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        socketChannel.close();
        key.attach(null);
        key.cancel();
      }

      if (conn != null) {
        if (!conn.closed) {
          U.trace("Closing connection", "connection", conn);
          conn.closed = true;
          assert conn.key == key;
          conn.key = null;
          connections.release(conn);
        }
      }

    } catch (IOException e) {
      e.printStackTrace();
    }
  }
Esempio n. 9
0
    private void cancel() {

      synchronized (guard) {
        selector.wakeup();
        key.cancel();
      }
    }
  /*
   * (non-Javadoc)
   *
   * @see java.lang.Runnable#run()
   */
  @Override
  public void run() {
    while (!stop) {
      try {
        selector.select(1000);
        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> it = selectedKeys.iterator();
        SelectionKey key = null;
        while (it.hasNext()) {
          key = it.next();
          it.remove();
          try {
            handleInput(key);
          } catch (Exception e) {
            if (key != null) {
              key.cancel();
              if (key.channel() != null) key.channel().close();
            }
          }
        }
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    // 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源
    if (selector != null)
      try {
        selector.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
  }
 public void serve(int port) throws IOException {
   ServerSocketChannel serverChannel = ServerSocketChannel.open();
   serverChannel.configureBlocking(false);
   ServerSocket ss = serverChannel.socket();
   InetSocketAddress address = new InetSocketAddress(port);
   // Binds the server to the selected port
   ss.bind(address);
   // Opens the Selector for handling channels
   Selector selector = Selector.open();
   // Registers the ServerSocket with the Selector to accept connections
   serverChannel.register(selector, SelectionKey.OP_ACCEPT);
   final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
   while (true) {
     try {
       // Waits for new events to process; blocks until the next incoming event
       selector.select();
     } catch (IOException e) {
       e.printStackTrace();
       break;
     }
     // Obtains all SelectionKey instances that received events
     Set<SelectionKey> readyKeys = selector.selectedKeys();
     Iterator<SelectionKey> iterator = readyKeys.iterator();
     while (iterator.hasNext()) {
       SelectionKey key = iterator.next();
       iterator.remove();
       try {
         // Checks if the event is a new connection ready to be accepted
         if (key.isAcceptable()) {
           ServerSocketChannel server = (ServerSocketChannel) key.channel();
           SocketChannel client = server.accept();
           client.configureBlocking(false);
           // Accepts client and registers it with the selector
           client.register(
               selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate());
           System.out.println("Accepted connection from " + client);
         }
         // Checks if the socket is ready for writing data
         if (key.isWritable()) {
           SocketChannel client = (SocketChannel) key.channel();
           ByteBuffer buffer = (ByteBuffer) key.attachment();
           while (buffer.hasRemaining()) {
             // Writes data to the connected client
             if (client.write(buffer) == 0) {
               break;
             }
           }
           // Closes the connection
           client.close();
         }
       } catch (IOException e) {
         key.cancel();
         try {
           key.channel().close();
         } catch (IOException e1) {
         }
       }
     }
   }
 }
Esempio n. 12
0
  private void write(SelectionKey key) {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    DataServerMessage sendMessage = mSendingData.get(socketChannel);

    boolean closeChannel = false;
    try {
      sendMessage.send(socketChannel);
    } catch (IOException e) {
      closeChannel = true;
      LOG.error(e.getMessage());
    }

    if (sendMessage.finishSending() || closeChannel) {
      try {
        key.channel().close();
      } catch (IOException e) {
        LOG.error(e.getMessage());
      }
      key.cancel();
      mReceivingData.remove(socketChannel);
      mSendingData.remove(socketChannel);
      sendMessage.close();
      mBlocksLocker.unlock(Math.abs(sendMessage.getBlockId()), sendMessage.getLockId());
    }
  }
Esempio n. 13
0
  private void handleInput(SelectionKey key) throws IOException {

    if (key != null && key.isValid()) {

      SocketChannel sc = (SocketChannel) key.channel();
      if (key.isConnectable()) {
        if (sc.finishConnect()) {
          sc.register(selector, SelectionKey.OP_READ);
          doWrite(sc);
        } else System.exit(1);
      }

      if (key.isReadable()) {
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        int readBytes = sc.read(readBuffer);
        if (readBytes > 0) {
          readBuffer.flip();
          byte[] bytes = new byte[readBuffer.remaining()];
          readBuffer.get(bytes);
          String body = new String(bytes, "UTF-8");
          System.out.println("Now is : " + body);
          this.stop = true;
        } else if (readBytes < 0) {
          key.cancel();
          sc.close();
        } else {

        }
      }
    }
  }
 void unregister(final SelectableChannel channel) {
   if (Thread.currentThread() != this) {
     final CountDownLatch latch = new CountDownLatch(1);
     this.addSelectorTask(
         new Runnable() {
           @Override
           public void run() {
             CommThread.this.unregister(channel);
             latch.countDown();
           }
         });
     try {
       latch.await();
     } catch (InterruptedException e) {
       throw new RuntimeException(e);
     }
   } else {
     SelectionKey key = null;
     key = channel.keyFor(this.selector);
     if (key != null) {
       key.cancel();
       key.attach(null);
     }
   }
 }
 public void closeInternal() {
   mKey.cancel();
   try {
     mChannel.close();
   } catch (IOException e) {
   }
 }
Esempio n. 16
0
  /**
   * @param remote Indicates who "generated" <code>code</code>.<br>
   *     <code>true</code> means that this endpoint received the <code>code</code> from the other
   *     endpoint.<br>
   *     false means this endpoint decided to send the given code,<br>
   *     <code>remote</code> may also be true if this endpoint started the closing handshake since
   *     the other endpoint may not simply echo the <code>code</code> but close the connection the
   *     same time this endpoint does do but with an other <code>code</code>. <br>
   */
  protected synchronized void closeConnection(int code, String message, boolean remote) {
    if (readystate == READYSTATE.CLOSED) {
      return;
    }

    if (key != null) {
      // key.attach( null ); //see issue #114
      key.cancel();
    }
    if (channel != null) {
      try {
        channel.close();
      } catch (IOException e) {
        wsl.onWebsocketError(this, e);
      }
    }
    try {
      this.wsl.onWebsocketClose(this, code, message, remote);
    } catch (RuntimeException e) {
      wsl.onWebsocketError(this, e);
    }
    if (draft != null) draft.reset();
    handshakerequest = null;

    readystate = READYSTATE.CLOSED;
    this.outQueue.clear();
  }
Esempio n. 17
0
    // Process keys that have become selected
    //
    void processSelectedKeys() throws IOException {
      for (Iterator i = sel.selectedKeys().iterator(); i.hasNext(); ) {

        // Retrieve the next key and remove it from the set
        SelectionKey sk = (SelectionKey) i.next();
        i.remove();

        // Retrieve the target and the channel
        Target t = (Target) sk.attachment();
        SocketChannel sc = (SocketChannel) sk.channel();

        // Attempt to complete the connection sequence
        try {
          if (sc.finishConnect()) {
            sk.cancel();
            t.connectFinish = System.currentTimeMillis();
            sc.close();
            printer.add(t);
          }
        } catch (IOException x) {
          sc.close();
          t.failure = x;
          printer.add(t);
        }
      }
    }
Esempio n. 18
0
  public void run() {
    System.out.println("Server started ...");
    System.out.println("Server listening on port: " + port);
    // 监听
    while (true) {
      try {
        int num = 0;
        num = selector.select();

        if (num > 0) {
          Set selectedKeys = selector.selectedKeys();
          Iterator it = selectedKeys.iterator();
          while (it.hasNext()) {
            SelectionKey key = (SelectionKey) it.next();
            it.remove();
            // 处理IO事件
            if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
              // Accept the new connection
              ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
              notifier.fireOnAccept();

              SocketChannel sc = ssc.accept();
              sc.configureBlocking(false);

              // 触发接受连接事件
              Request request = new Request(sc);
              notifier.fireOnAccepted(request);

              // 注册读操作,以进行下一步的读操作
              sc.register(selector, SelectionKey.OP_READ, request);
            } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
              Reader.processRequest(key); // 提交读服务线程读取客户端数据
              key.cancel();
            } else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
              Writer.processRequest(key); // 提交写服务线程向客户端发送回应数据
              key.cancel();
            }
          }
        } else {
          addRegister(); // 在Selector中注册新的写通道
        }
      } catch (Exception e) {
        notifier.fireOnError("Error occured in Server: " + e.getMessage());
        continue;
      }
    }
  }
 public void close() {
   key.cancel();
   try {
     channel.close();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }
  /**
   * This is used to cancel any selection keys that have previously been selected with an interested
   * I/O event. Performing a cancel here ensures that on a the next select the associated channel is
   * not considered, this ensures the select does not break.
   */
  private void cancel() throws IOException {
    Collection<SelectionKey> list = this.table.values();

    for (SelectionKey key : list) {
      key.cancel();
    }
    this.table.clear();
  }
Esempio n. 21
0
 /**
  * cancel the key registion and close the channel
  *
  * @param k
  */
 private void cancelAndClose(SelectionKey k) {
   k.cancel();
   try {
     k.channel().close();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }
Esempio n. 22
0
  public void listener() {

    try {
      ServerSocketChannel ssc = ServerSocketChannel.open();
      ServerSocket server = ssc.socket();
      Selector selector = Selector.open();

      server.bind(new InetSocketAddress(port));
      ssc.configureBlocking(false);
      ssc.register(selector, SelectionKey.OP_ACCEPT);

      while (true) {
        selector.select();
        Set keys = selector.selectedKeys();
        Iterator it = keys.iterator();

        while (it.hasNext()) {
          SelectionKey key = (SelectionKey) it.next();

          if (key.isAcceptable()) {
            Socket listen = server.accept();
            SocketChannel sc = listen.getChannel();
            sc.configureBlocking(false);
            sc.register(selector, SelectionKey.OP_READ);
          }

          if (key.isReadable() && key.isValid()) {
            ByteBuffer bb = ByteBuffer.allocate(512);
            SocketChannel st = (SocketChannel) key.channel();
            int byteRead = st.read(bb);
            bb.flip();
            if (byteRead == -1) {
              key.cancel();
              st.close();

            } else {
              analyseData(bb);
              key.cancel();
            }
          }
        }
        keys.clear();
      }
    } catch (Exception e) {
    }
  }
Esempio n. 23
0
 /**
  * Disconnects this session from the server by canceling the registered key and closing the socket
  * channel.
  *
  * @param forced if the session must be disconnected because of an IO issue.
  */
 public void disconnect(boolean forced) {
   try {
     if (!forced && player.getCombatBuilder().inCombat()) {
       combatLogout = true;
       key.attach(null);
       key.cancel();
       channel.close();
       World.submit(
           new Task(150, false) {
             @Override
             public void execute() {
               if (!player.getCombatBuilder().inCombat()) {
                 disconnect(true);
                 this.cancel();
               }
             }
           });
       return;
     }
     packetDisconnect = forced;
     if (state == IOState.LOGGED_IN) {
       if (player.getOpenShop() != null)
         Shop.SHOPS.get(player.getOpenShop()).getPlayers().remove(player);
       World.getTaskQueue().cancel(player.getCombatBuilder());
       World.getTaskQueue().cancel(player);
       player.setSkillAction(false);
       World.getPlayers().remove(player);
       MinigameHandler.execute(player, m -> m.onLogout(player));
       player.getTradeSession().reset(false);
       player.getPrivateMessage().updateOtherList(false);
       if (FightCavesHandler.remove(player)) player.move(new Position(2399, 5177));
       player.save();
     }
     key.attach(null);
     key.cancel();
     channel.close();
     ConnectionHandler.remove(host);
     logger.info(
         state == IOState.LOGGED_IN
             ? player + " has logged " + "out."
             : this + " has logged out.");
     state = IOState.LOGGED_OUT;
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
  public void stop() {
    try {
      lock.lock();

      if (networkJob != null && !networkJob.isCancelled()) {
        networkJob.cancel(true);
        networkJob = null;
      }

      try {
        if (selector != null) {

          selector.wakeup();

          boolean isContinue = true;
          while (isContinue) {
            try {
              for (SelectionKey selectionKey : selector.keys()) {
                selectionKey.channel().close();
                selectionKey.cancel();
              }
              isContinue = false; // continue till all keys are cancelled
            } catch (ConcurrentModificationException e) {
              logger.warn(
                  "An exception occurred while closing a selector key : '{}'", e.getMessage());
            }
          }

          selector.close();
        }
      } catch (IOException e) {
        logger.warn("An exception occurred while closing the selector : '{}'", e.getMessage());
      }

      if (broadcastKey != null) {
        try {
          broadcastKey.channel().close();
        } catch (IOException e) {
          logger.warn(
              "An exception occurred while closing the broadcast channel : '{}'", e.getMessage());
        }
      }

      if (unicastKey != null) {
        try {
          unicastKey.channel().close();
        } catch (IOException e) {
          logger.warn(
              "An exception occurred while closing the unicast channel : '{}'", e.getMessage());
        }
      }

      ipAddress = null;
    } finally {
      lock.unlock();
    }
  }
Esempio n. 25
0
 /* Flush our internal buffer of cancelled keys */
 private void cancelKeys() {
   Iterator cancelledKeys = this.cancelledKeys.entrySet().iterator();
   while (cancelledKeys.hasNext()) {
     Map.Entry entry = (Map.Entry) cancelledKeys.next();
     SelectionKey key = (SelectionKey) entry.getValue();
     key.cancel();
     cancelledKeys.remove();
   }
 }
  /**
   * This method is used to expire registered operations that remain idle within the selector.
   * Operations specify a time at which point they wish to be canceled if the I/O event they wait on
   * has not arisen. This will enables the canceled operation to be canceled so that the resources
   * it occupies can be released.
   *
   * @param key this is the selection key for the operation
   * @param action this is the actual action to be canceled
   */
  private void expire(SelectionKey key, Action action) throws IOException {
    Action cancel = new CancelAction(action);

    if (key != null) {
      key.attach(cancel);
      key.cancel();
    }
    this.process(key);
  }
Esempio n. 27
0
 private void closeConnection() {
   // remove from the selector.
   _skey.cancel();
   try {
     _sChannel.close();
   } catch (IOException ignored) {
     ignored = null;
   }
 }
  protected void close(DatagramChannel handle) throws Exception {
    SelectionKey key = handle.keyFor(selector);

    if (key != null) {
      key.cancel();
    }

    handle.disconnect();
    handle.close();
  }
Esempio n. 29
0
  public void shutdown(final long period, final TimeUnit timeUnit) {
    channelDispatcher.stop();
    for (SelectionKey selectionKey : socketChannelSelector.keys()) {
      final AbstractChannelReader reader = (AbstractChannelReader) selectionKey.attachment();
      selectionKey.cancel();
      if (reader != null) {
        while (!reader.isClosed()) {
          try {
            Thread.sleep(channelReaderFrequencyMSecs);
          } catch (InterruptedException e) {
          }
        }
        final ScheduledFuture<?> readerFuture = reader.getScheduledFuture();
        readerFuture.cancel(false);
      }
      IOUtils.closeQuietly(
          selectionKey
              .channel()); // should already be closed via reader, but if reader did not exist...
    }
    IOUtils.closeQuietly(socketChannelSelector);

    for (SelectionKey selectionKey : serverSocketSelector.keys()) {
      selectionKey.cancel();
      IOUtils.closeQuietly(selectionKey.channel());
    }
    IOUtils.closeQuietly(serverSocketSelector);
    executor.shutdown();
    try {
      executor.awaitTermination(period, timeUnit);
    } catch (final InterruptedException ex) {
      LOGGER.warn("Interrupted while trying to shutdown executor");
    }
    final int currentBufferPoolSize = bufferPool.size();
    final String warning =
        (currentBufferPoolSize != initialBufferPoolSize)
            ? "Initial buffer count="
                + initialBufferPoolSize
                + " Current buffer count="
                + currentBufferPoolSize
                + " Could indicate a buffer leak.  Ensure all consumers are executed until they complete."
            : "";
    LOGGER.info("Channel listener shutdown. " + warning);
  }
 /** Do connection-close cleanup on a given SelectionKey. */
 protected void cleanupSelectionKey(SelectionKey key) {
   // remove the records from the two maps
   FrameBuffer buffer = (FrameBuffer) key.attachment();
   if (buffer != null) {
     // close the buffer
     buffer.close();
   }
   // cancel the selection key
   key.cancel();
 }