Example #1
0
  @Override
  protected void writeOP(SelectionKey key) throws IOException {
    RapidoidConnection conn = (RapidoidConnection) key.attachment();
    SocketChannel socketChannel = (SocketChannel) key.channel();

    checkOnSameThread();

    try {
      int wrote = conn.output.writeTo(socketChannel);

      conn.output.deleteBefore(wrote);

      boolean complete = conn.output.size() == 0;

      if (conn.closeAfterWrite() && complete) {
        close(conn);
      } else {
        if (complete) {
          key.interestOps(SelectionKey.OP_READ);
        } else {
          key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
        }
        conn.wrote(complete);
      }
    } catch (IOException e) {
      close(conn);
    }
  }
Example #2
0
  /** Handle new OP_CONNECT ops. */
  protected void onConnectOp(Context ctx, ConnectChannelOperation selectionKeyOp)
      throws IOException {
    SocketChannel socketChannel = (SocketChannel) selectionKeyOp.getChannel();
    SocketAddress remoteAddress = selectionKeyOp.getRemoteAddress();
    CallbackHandler callbackHandler = selectionKeyOp.getCallbackHandler();

    CallbackHandlerSelectionKeyAttachment attachment =
        new CallbackHandlerSelectionKeyAttachment(callbackHandler);

    SelectionKey key = socketChannel.register(selector, 0, attachment);
    attachment.associateKey(key);

    boolean isConnected;
    try {
      isConnected = socketChannel.connect(remoteAddress);
    } catch (Exception e) {
      if (logger.isLoggable(Level.FINE)) {
        logger.log(Level.FINE, "Exception occured when tried to connect socket", e);
      }

      // set isConnected to true to let callback handler to know about the problem happened
      isConnected = true;
    }

    // if channel was connected immediately or exception occured
    if (isConnected) {
      onConnectInterest(key, ctx);
    } else {
      key.interestOps(SelectionKey.OP_CONNECT);
    }
  }
  /**
   * Start the server running - accepting connections, receiving messages. If the server is already
   * running, it will not be started again. This method is designed to be called in its own thread
   * and will not return until the server is stopped.
   *
   * @throws RuntimeException if the server fails
   */
  public void run() {
    // ensure that the server is not started twice
    if (!state.compareAndSet(State.STOPPED, State.RUNNING)) {
      started(true);
      return;
    }

    Selector selector = null;
    ServerSocketChannel server = null;
    try {
      selector = Selector.open();
      server = ServerSocketChannel.open();
      server.socket().bind(new InetSocketAddress(port));
      server.configureBlocking(false);
      server.register(selector, SelectionKey.OP_ACCEPT);
      started(false);
      while (state.get() == State.RUNNING) {
        selector.select(100); // check every 100ms whether the server has been requested to stop
        for (Iterator<SelectionKey> it = selector.selectedKeys().iterator(); it.hasNext(); ) {
          SelectionKey key = it.next();
          try {
            // remove key from the ready list
            it.remove();
            if (key.isConnectable()) {
              ((SocketChannel) key.channel()).finishConnect();
            }
            if (key.isAcceptable()) {
              // accept connection
              SocketChannel client = server.accept();
              client.configureBlocking(false);
              client.socket().setTcpNoDelay(true);
              // channel is registered for further events such as read or write
              SelectionKey acceptKey = client.register(selector, SelectionKey.OP_READ);
              connection(acceptKey);
            }
            if (key.isReadable()) {
              for (ByteBuffer message : readIncomingMessage(key)) {
                messageReceived(message, key);
              }
            }
          } catch (IOException ioe) {
            resetKey(key);
            disconnected(key);
          }
        }
      }
    } catch (Throwable e) {
      throw new RuntimeException("Server failure: " + e.getMessage());
    } finally {
      try {
        selector.close();
        server.socket().close();
        server.close();
        state.set(State.STOPPED);
        stopped();
      } catch (Exception e) {
        // do nothing - server failed
      }
    }
  }
  public void actionHandler(SelectionKey key) throws IOException {
    if (key.isAcceptable()) {
      ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
      SocketChannel socketChannel = serverChannel.accept();
      socketChannel.configureBlocking(false);
      socketChannel.register(roller, SelectionKey.OP_READ);
    } else if (key.isReadable()) {
      ByteBuffer buffer = ByteBuffer.allocate(16);
      SocketChannel socketChannel = (SocketChannel) key.channel();
      socketChannel.read(buffer);
      buffer.flip();
      String temp = decode(buffer);
      StringBuffer strBuffer = stringLocal.get();
      if (strBuffer == null) {
        strBuffer = new StringBuffer();
      }

      strBuffer.append(temp);

      if (temp.equals("\r\n")) {
        System.out.println(strBuffer.toString());
        strBuffer = null;
      }
      stringLocal.set(strBuffer);
    }
  }
Example #5
0
 /**
  * This implementation defers to the {@link #accept(SelectionKey)} method if a connection is
  * pending. In all other cases it defers to it's parent.
  *
  * @param key The {@link SelectionKey} for the socket on which an I/O operation is pending.
  * @throws IOException if an error occurs while processing the pending event.
  */
 protected void handleSelectionKeyOperation(SelectionKey key) throws IOException {
   if (key.isValid() && key.isAcceptable()) {
     this.accept(key);
   } else {
     super.handleSelectionKeyOperation(key);
   }
 }
 @GuardedBy("lock")
 private void setWriteOps() {
   // Make sure we are registered to get updated when writing is available again
   key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
   // Refresh the selector to make sure it gets the new interestOps
   key.selector().wakeup();
 }
Example #7
0
  @Override
  public void run() {
    try {
      while (true) {
        this.selector.select(SELECT_MILLISECONDS);
        if (Thread.interrupted()) break;

        Iterator<SelectionKey> i = this.selector.selectedKeys().iterator();
        while (i.hasNext()) {
          SelectionKey key = i.next();
          SelectableChannel channel = key.channel();
          handleReadableChannel(key, channel);
          handleWritableChannel(key, channel);
          i.remove();
        }
      }
    } catch (ClosedByInterruptException e) {
      // User-requested interrupt, so clean up
    } catch (IOException e) {
      reportIOException(e);
    }

    for (Map.Entry<SelectableChannel, SelectableChannel> e : this.outputs.entrySet()) {
      closeChannelAndReportException(e.getKey());
      closeChannelAndReportException(e.getValue());
    }

    for (SelectableChannel c : this.outputBuffers.keySet()) closeChannelAndReportException(c);
  }
Example #8
0
 public void run() {
   try {
     while (!flag) {
       System.out.println("waiting connected.......");
       selector.select();
       Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
       while (keys.hasNext()) {
         SelectionKey key = keys.next();
         keys.remove();
         if (key.isAcceptable()) {
           ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
           SocketChannel sc = ssc.accept();
           sc.configureBlocking(false);
           SelectionKey clientKey = sc.register(selector, SelectionKey.OP_READ);
           System.out.println(sc.socket().getInetAddress().getHostAddress() + " 已连接");
         }
         if (key.isReadable()) {
           read(key);
         }
       }
     }
   } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
   }
 }
  private void loop() {
    while (true) {
      try {
        selector.select();
        Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
        while (selectedKeys.hasNext()) {
          SelectionKey key = selectedKeys.next();
          selectedKeys.remove();

          if (!key.isValid()) {
            continue;
          }

          // Check what event is available and deal with it
          if (key.isAcceptable()) {
            accept(key);
          } else if (key.isReadable()) {
            read(key);
          } else if (key.isWritable()) {
            write(key);
          }
        }

      } catch (Exception e) {
        e.printStackTrace();
        System.exit(1);
      }
    }
  }
  void unregisterChannels(SelectionKeyRegistrationReference registrationReference)
      throws Exception {

    registrationReference.cancelRegistration();

    SelectorIntraband defaultIntraband = (SelectorIntraband) registrationReference.getIntraband();

    Selector selector = defaultIntraband.selector;

    Set<SelectionKey> keys = selector.keys();

    while (!keys.isEmpty()) {
      selector.wakeup();
    }

    SelectionKey readSelectionKey = registrationReference.readSelectionKey;
    SelectionKey writeSelectionKey = registrationReference.writeSelectionKey;

    SelectableChannel readSelectableChannel = readSelectionKey.channel();
    SelectableChannel writeSelectableChannel = writeSelectionKey.channel();

    while (readSelectableChannel.keyFor(selector) != null) ;
    while (writeSelectableChannel.keyFor(selector) != null) ;

    writeSelectableChannel.close();
    readSelectableChannel.close();
  }
Example #11
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);
        }
      }
    }
Example #12
0
  private void write(SelectionKey key) throws IOException {
    SocketChannel ch = (SocketChannel) key.channel();
    int count = 0;

    synchronized (pendingData) {
      List queue = (List) pendingData.get(ch);
      /**
       * Null exception alert: This can happen once a connection was established. Check send() for
       * more information.
       */
      if (queue == null) return;

      while (!queue.isEmpty()) {
        ByteBuffer buf = (ByteBuffer) queue.get(0);
        ch.write(buf);

        count += buf.capacity() - buf.remaining();
        if (buf.remaining() > 0) break;
        queue.remove(0);
      }

      if (queue.isEmpty()) key.interestOps(SelectionKey.OP_READ);
    }

    if (!listener.handleWrite(ch, count)) close(ch);
  }
Example #13
0
  @Override
  public void run() {
    try {
      System.out.println("[Server Opened]");
      selector = Selector.open();
      ssc.register(selector, SelectionKey.OP_ACCEPT);
      while (true) {
        int canalsPreparats = selector.select();
        if (canalsPreparats == 0) {
          continue;
        }
        Set<SelectionKey> clausSeleccionades = selector.selectedKeys();
        Iterator<SelectionKey> iterador = clausSeleccionades.iterator();
        while (iterador.hasNext()) {
          SelectionKey clau = iterador.next();

          // CONCURRENCIA claus
          // Les claus son un recurs compartit, ja que quan finalitza
          // el joc, el métode update() les cancela. Per aquest motiu
          // quan en fem us, synchronitzem el objecte, i comprovem
          // que siguin vàlides
          synchronized (this) {
            if (clau.isValid() && clau.isAcceptable()) {
              ferAccept(clau);
            } else if (clau.isValid() && clau.isReadable()) {
              rebre(clau);
            }
          }
          iterador.remove();
        }
      }
    } catch (IOException ex) {
    }
  }
Example #14
0
  @Override
  protected void doProcessing() {

    SocketChannel socketChannel;
    while ((socketChannel = accepted.poll()) != null) {
      U.debug("incoming connection", "address", socketChannel.socket().getRemoteSocketAddress());

      try {
        SelectionKey newKey = socketChannel.register(selector, SelectionKey.OP_READ);
        RapidoidConnection conn = connections.get();
        conn.key = newKey;

        if (isProtocolListener) {
          conn.setListener((ConnectionListener) protocol);
        }

        newKey.attach(conn);

      } catch (ClosedChannelException e) {
        U.warn("Closed channel", e);
      }
    }

    synchronized (done) {
      for (int i = 0; i < done.size(); i++) {
        RapidoidConnection conn = done.get(i);
        if (conn.key != null && conn.key.isValid()) {
          conn.key.interestOps(SelectionKey.OP_WRITE);
        }
      }
      done.clear();
    }
  }
    private void dispose(Selector localSelector, LinkedBlockingQueue localSelectorTasks) {
      Assert.eval(Thread.currentThread() == this);

      if (localSelector != null) {

        for (Object element : localSelector.keys()) {
          try {
            SelectionKey key = (SelectionKey) element;
            cleanupChannel(key.channel(), null);
          } catch (Exception e) {
            logger.warn("Exception trying to close channel", e);
          }
        }

        try {
          localSelector.close();
        } catch (Exception e) {
          if ((Os.isMac()) && (Os.isUnix()) && (e.getMessage().equals("Bad file descriptor"))) {
            // I can't find a specific bug about this, but I also can't seem to prevent the
            // exception on the Mac.
            // So just logging this as warning.
            logger.warn("Exception trying to close selector: " + e.getMessage());
          } else {
            logger.error("Exception trying to close selector", e);
          }
        }
      }
    }
Example #16
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);
    }
  }
    private void doConnect(SelectionKey key) {
      SocketChannel sc = (SocketChannel) key.channel();
      TCConnectionImpl conn = (TCConnectionImpl) key.attachment();

      try {
        if (sc.finishConnect()) {
          sc.register(selector, SelectionKey.OP_READ, conn);
          conn.finishConnect();
        } else {
          String errMsg = "finishConnect() returned false, but no exception thrown";

          if (logger.isInfoEnabled()) {
            logger.info(errMsg);
          }

          conn.fireErrorEvent(new Exception(errMsg), null);
        }
      } catch (IOException ioe) {
        if (logger.isInfoEnabled()) {
          logger.info("IOException attempting to finish socket connection", ioe);
        }

        conn.fireErrorEvent(ioe, null);
      }
    }
Example #18
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());
    }
  }
Example #19
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 {

        }
      }
    }
  }
Example #20
0
 /** Немедленно выключает интересуемое действие OP_READ */
 protected void disableReadInterest() {
   try {
     _selectionKey.interestOps(_selectionKey.interestOps() & ~SelectionKey.OP_READ);
   } catch (CancelledKeyException e) {
     // ignore
   }
 }
Example #21
0
    @Override
    protected SelectChannelEndPoint newEndPoint(
        SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException {
      // We're connected, cancel the connect timeout
      Timeout.Task connectTimeout = _connectingChannels.remove(channel);
      if (connectTimeout != null) connectTimeout.cancel();
      if (LOG.isDebugEnabled())
        LOG.debug("Channels with connection pending: {}", _connectingChannels.size());

      // key should have destination at this point (will be replaced by endpoint after this call)
      HttpDestination dest = (HttpDestination) key.attachment();

      SelectChannelEndPoint scep =
          new SelectChannelEndPoint(channel, selectSet, key, (int) _httpClient.getIdleTimeout());
      AsyncEndPoint ep = scep;

      if (dest.isSecure()) {
        LOG.debug("secure to {}, proxied={}", channel, dest.isProxied());
        ep = new UpgradableEndPoint(ep, newSslEngine(channel));
      }

      AsyncConnection connection =
          selectSet.getManager().newConnection(channel, ep, key.attachment());
      ep.setConnection(connection);

      AbstractHttpConnection httpConnection = (AbstractHttpConnection) connection;
      httpConnection.setDestination(dest);

      if (dest.isSecure() && !dest.isProxied()) ((UpgradableEndPoint) ep).upgrade();

      dest.onNewConnection(httpConnection);

      return scep;
    }
Example #22
0
  @Override
  public void run() {
    try {
      selector = Selector.open();

      while (true) {
        processSelectionQueue();

        int nKeys = selector.select(selectWaitTime); // blocking
        if (nKeys == 0) {
          continue;
        } else {
          logger.trace(String.format("Selector %d, keys num: %d", selectorNum, nKeys));
        }

        Set<SelectionKey> keys = selector.selectedKeys();
        Iterator<SelectionKey> iter = keys.iterator();

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

          logger.trace("Key operations: " + key.readyOps());

          if (key.isWritable()) {
            doWrite(key);
          }
        }
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
  private void processKey(SelectionKey key) {

    try {

      if (key.isReadable()) {
        final DatagramChannel socketChannel = (DatagramChannel) key.channel();
        reader.readAll(socketChannel);
      }

      if (key.isWritable()) {
        final DatagramChannel socketChannel = (DatagramChannel) key.channel();
        try {
          int bytesJustWritten = writer.writeAll(socketChannel);
          contemplateThrottleWrites(bytesJustWritten);
        } catch (NotYetConnectedException e) {
          if (LOG.isDebugEnabled()) LOG.debug("", e);
          serverConnector.connectLater();
        } catch (IOException e) {
          if (LOG.isDebugEnabled()) LOG.debug("", e);
          serverConnector.connectLater();
        }
      }
    } catch (Exception e) {
      LOG.error("", e);
      if (!isClosed) closeEarlyAndQuietly(key.channel());
    }
  }
  // actual connection logic
  private void _connect() throws IOException {
    // Continuous loop that is only supposed to end when "close" is called.

    selector.select();
    Set<SelectionKey> keys = selector.selectedKeys();
    Iterator<SelectionKey> i = keys.iterator();

    while (i.hasNext()) {
      SelectionKey key = i.next();
      i.remove();
      if (key.isConnectable()) {
        if (socketChannel.isConnectionPending()) {
          socketChannel.finishConnect();
        }
        socketChannel.register(selector, SelectionKey.OP_READ);
        _writeHandshake();
      }
      if (key.isReadable()) {
        try {
          _read();
        } catch (NoSuchAlgorithmException nsa) {
          this.onError(nsa);
        }
      }
    }
  }
Example #25
0
  private void handle(SelectionKey key) throws IOException {
    // TODO Auto-generated method stub

    ServerSocketChannel server = null;
    SocketChannel client = null;
    String receiveText = null;
    int count = 0;

    if (key.isAcceptable()) {
      // client require accept events
      server = (ServerSocketChannel) key.channel();
      client = server.accept();
      client.configureBlocking(false);
      client.register(selector, SelectionKey.OP_READ);
    } else if (key.isReadable()) {
      // 如果是read事件,则直接读取
      client = (SocketChannel) key.channel();
      recBuffer.clear();
      count = client.read(recBuffer);
      if (count > 0) {
        recBuffer.flip();
        receiveText = decode.decode(recBuffer.asReadOnlyBuffer()).toString();
        System.out.println(client.toString() + ":" + receiveText);
        sendBuffer.clear();
        sendBuffer.put((sdf.format(new Date()) + "服务器收到你的消息").getBytes());
        sendBuffer.flip();
        client.write(sendBuffer);
        dispatch(client, receiveText);
        client = (SocketChannel) key.channel();
        client.register(selector, SelectionKey.OP_READ);
      }
    }
  }
Example #26
0
  public void registerInterestOps(EventHandler eventHandler) {
    if (orb.transportDebugFlag) {
      dprint(".registerInterestOps:-> " + eventHandler);
    }

    SelectionKey selectionKey = eventHandler.getSelectionKey();
    if (selectionKey.isValid()) {
      int ehOps = eventHandler.getInterestOps();
      SelectionKeyAndOp keyAndOp = new SelectionKeyAndOp(selectionKey, ehOps);
      synchronized (interestOpsList) {
        interestOpsList.add(keyAndOp);
      }
      // tell Selector Thread there's an update to a SelectorKey's Ops
      selector.wakeup();
    } else {
      wrapper.selectionKeyInvalid(eventHandler.toString());
      if (orb.transportDebugFlag) {
        dprint(".registerInterestOps: EventHandler SelectionKey not valid " + eventHandler);
      }
    }

    if (orb.transportDebugFlag) {
      dprint(".registerInterestOps:<- ");
    }
  }
Example #27
0
  /** {@inheritDoc} */
  public SelectableChannel acceptWithoutRegistration(SelectionKey key) throws IOException {
    boolean isAccepted;
    int retryNum = 0;
    do {
      try {
        isAccepted = true;
        return ((ServerSocketChannel) key.channel()).accept();
      } catch (IOException ex) {
        if (!key.isValid()) throw ex;

        isAccepted = false;
        try {
          // Let's try to recover here from too many open file
          Thread.sleep(1000);
        } catch (InterruptedException ex1) {
          throw new IOException(ex1.getMessage());
        }
        logger.log(
            Level.WARNING,
            LogMessages.WARNING_GRIZZLY_TCPSELECTOR_HANDLER_ACCEPTCHANNEL_EXCEPTION(),
            ex);
      }
    } while (!isAccepted && retryNum++ < maxAcceptRetries);

    throw new IOException("Accept retries exceeded");
  }
 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 handleAccept(SelectionKey key) throws IOException {
   ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
   SocketChannel socketChannel = serverSocketChannel.accept();
   log.info("Server: accept client socket " + socketChannel);
   socketChannel.configureBlocking(false);
   socketChannel.register(key.selector(), SelectionKey.OP_READ);
 }
Example #30
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();
    }
  }