/**
   * Closes all connected clients sockets, then closes the underlying ServerSocketChannel,
   * effectively killing the server socket selectorthread, freeing the port the server was bound to
   * and stops all internal workerthreads.
   *
   * <p>If this method is called before the server is started it will never start.
   *
   * @param timeout Specifies how many milliseconds shall pass between initiating the close
   *     handshakes with the connected clients and closing the servers socket channel.
   * @throws IOException When {@link ServerSocketChannel}.close throws an IOException
   * @throws InterruptedException
   */
  public void stop(int timeout) throws IOException, InterruptedException {
    if (!isclosed.compareAndSet(false, true)) {
      return;
    }

    synchronized (connections) {
      for (WebSocket ws : connections) {
        ws.close(CloseFrame.GOING_AWAY);
      }
    }
    synchronized (this) {
      if (selectorthread != null) {
        if (Thread.currentThread() != selectorthread) {}

        if (selectorthread != Thread.currentThread()) {
          selectorthread.interrupt();
          selectorthread.join();
        }
      }
      if (decoders != null) {
        for (WebSocketWorker w : decoders) {
          w.interrupt();
        }
      }
      if (server != null) {
        server.close();
      }
    }
  }
示例#2
0
 private void handleFatal(WebSocket conn, RuntimeException e) {
   onError(conn, e);
   try {
     selector.close();
   } catch (IOException e1) {
     onError(null, e1);
   }
   for (WebSocketWorker w : decoders) {
     w.interrupt();
   }
 }
  // Runnable IMPLEMENTATION /////////////////////////////////////////////////
  public void run() {
    synchronized (this) {
      if (selectorthread != null)
        throw new IllegalStateException(getClass().getName() + " can only be started once.");
      selectorthread = Thread.currentThread();
      if (isclosed.get()) {
        return;
      }
    }
    selectorthread.setName("WebsocketSelector" + selectorthread.getId());
    try {
      server = ServerSocketChannel.open();
      server.configureBlocking(false);
      ServerSocket socket = server.socket();
      socket.setReceiveBufferSize(WebSocketImpl.RCVBUF);
      socket.bind(address);
      selector = Selector.open();
      server.register(selector, server.validOps());
    } catch (IOException ex) {
      handleFatal(null, ex);
      return;
    }
    try {
      while (!selectorthread.isInterrupted()) {
        SelectionKey key = null;
        WebSocketImpl conn = null;
        try {
          selector.select();
          Set<SelectionKey> keys = selector.selectedKeys();
          Iterator<SelectionKey> i = keys.iterator();

          while (i.hasNext()) {
            key = i.next();

            if (!key.isValid()) {
              // Object o = key.attachment();
              continue;
            }

            if (key.isAcceptable()) {
              if (!onConnect(key)) {
                key.cancel();
                continue;
              }

              SocketChannel channel = server.accept();
              channel.configureBlocking(false);
              WebSocketImpl w = wsf.createWebSocket(this, drafts, channel.socket());
              w.key = channel.register(selector, SelectionKey.OP_READ, w);
              w.channel = wsf.wrapChannel(channel, w.key);
              i.remove();
              allocateBuffers(w);
              continue;
            }

            if (key.isReadable()) {
              conn = (WebSocketImpl) key.attachment();
              ByteBuffer buf = takeBuffer();
              try {
                if (SocketChannelIOHelper.read(buf, conn, conn.channel)) {
                  if (buf.hasRemaining()) {
                    conn.inQueue.put(buf);
                    queue(conn);
                    i.remove();
                    if (conn.channel instanceof WrappedByteChannel) {
                      if (((WrappedByteChannel) conn.channel).isNeedRead()) {
                        iqueue.add(conn);
                      }
                    }
                  } else pushBuffer(buf);
                } else {
                  pushBuffer(buf);
                }
              } catch (IOException e) {
                pushBuffer(buf);
                throw e;
              }
            }
            if (key.isWritable()) {
              conn = (WebSocketImpl) key.attachment();
              if (SocketChannelIOHelper.batch(conn, conn.channel)) {
                if (key.isValid()) key.interestOps(SelectionKey.OP_READ);
              }
            }
          }
          while (!iqueue.isEmpty()) {
            conn = iqueue.remove(0);
            WrappedByteChannel c = ((WrappedByteChannel) conn.channel);
            ByteBuffer buf = takeBuffer();
            try {
              if (SocketChannelIOHelper.readMore(buf, conn, c)) iqueue.add(conn);
              if (buf.hasRemaining()) {
                conn.inQueue.put(buf);
                queue(conn);
              } else {
                pushBuffer(buf);
              }
            } catch (IOException e) {
              pushBuffer(buf);
              throw e;
            }
          }
        } catch (CancelledKeyException e) {
          // an other thread may cancel the key
        } catch (ClosedByInterruptException e) {
          return; // do the same stuff as when InterruptedException is thrown
        } catch (IOException ex) {
          if (key != null) key.cancel();
          handleIOException(key, conn, ex);
        } catch (InterruptedException e) {
          return; // FIXME controlled shutdown (e.g. take care of buffermanagement)
        }
      }

    } catch (RuntimeException e) {
      // should hopefully never occur
      handleFatal(null, e);
    } finally {
      if (decoders != null) {
        for (WebSocketWorker w : decoders) {
          w.interrupt();
        }
      }
      if (server != null) {
        try {
          server.close();
        } catch (IOException e) {
          onError(null, e);
        }
      }
    }
  }