有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java当用户重新加载网页并且websocket会话超时时,如何正确关闭服务器端的websocket会话?

java.lang.IllegalStateException当用户重新加载页面时onClose方法被调用,我得到一个异常,即socket已经关闭。因此,我无法清理websocket会话关闭时停止的其他线程中的一些内容。如果用户关闭会话而不重新加载页面(它基本上是websocket上的服务器端终端),那么一切都很好。我在tomcat8上

问题

  1. 如果用户重新加载页面,如何正确关闭服务器上的websocket会话
  2. 当webshocket会话超时时,我该如何做一些事情

以下是为websocket连接提供服务器的代码

@ServerEndpoint(value = "/ws/{clientId}", configurator = HttpSessionConfigurator.class)
public class WSSession {
    public static final long DEFAULT_TIMEOUT = 3600000;
    public static final int DEFAULT_TIMEOUT_IN_SECONDS = 3600;

    private Session wsSession;
    private HttpSession httpSession;

    private static final ConfigService configService;

    static {
        configService = ConfigServiceFactory.getConfigService(System
                .getenv("ENVRIRONMENT"));
    }

    @OnOpen
    public void onOpen(@PathParam("clientId") String clientId, Session session,
            EndpointConfig config) throws IOException {
        Logger logger = Logger.getLogger(clientId);
        try {
            FileHandler fh = new FileHandler(configService.logDirectory()
                    .toString() + "/" + clientId);
            SimpleFormatter formatter = new SimpleFormatter();
            fh.setFormatter(formatter);
            logger.addHandler(fh);
            logger.setLevel(Level.INFO);
        } catch (SecurityException | IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        System.out.println("Got ID: " + clientId);
        // TODO: Get the max timeout from configuration
        session.setMaxIdleTimeout(DEFAULT_TIMEOUT);
        ConnectionDetails cd = configService.getConnectionDetails(clientId);
        this.wsSession = session;
        this.httpSession = (HttpSession) config.getUserProperties().get(
                HttpSession.class.getName());
        if (this.httpSession.getAttribute(SessionProperties.WS_SESSION.value()) != null
                && this.httpSession.getAttribute(SessionProperties.WS_SESSION
                        .value()) != session) {
            Session wSession = (Session) this.httpSession
                    .getAttribute(SessionProperties.WS_SESSION.value());
            if (wSession.isOpen()) {
                wSession.close();
            }
        }
        // TODO: Code changes for password based login
        // For now there is no password login.
        // TODO: For now the passphrase is NULL and strict checking is disabled
        this.wsSession = session;
        try {
            Connection connection = new Connection(cd.getHost(), cd.getPort());
            connection.connect();
            boolean authenticated = connection.authenticateWithPublicKey(
                    cd.getUserName(), cd.getPrivateKey().toCharArray(), null);
            if (authenticated) {
                ch.ethz.ssh2.Session sshSession = connection.openSession();
                sshSession.requestPTY("xterm", 120, 40, 14, 14, null);
                OutputStream out = sshSession.getStdin();
                InputStream in = new StreamGobbler(sshSession.getStdout());
                sshSession.startShell();
                Basic basicRemote = session.getBasicRemote();
                Async asyncRemote = session.getAsyncRemote();
                httpSession.setAttribute(SessionProperties.CLIENT_ID.value(),
                        clientId);
                httpSession.setAttribute(SessionProperties.SSH_SESSION.value(),
                        sshSession);
                httpSession.setAttribute(SessionProperties.IN_SSH.value(), out);
                httpSession.setAttribute(SessionProperties.OUT_SSH.value(), in);
                httpSession.setAttribute(
                        SessionProperties.BASIC_REMOTE.value(), basicRemote);
                httpSession.setAttribute(SessionProperties.WS_SESSION.value(),
                        wsSession);
                httpSession.setAttribute(
                        SessionProperties.ASYNC_REMOTE.value(), asyncRemote);
                Thread worker = new Thread(new OutputTask(httpSession,
                        wsSession));
                worker.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        // IN_SSH is connection from this machine to remote machine.
        // OUT_SSH is connection from this remote machine to this machine.
        byte[] bytes = message.getBytes();
        OutputStream out = (OutputStream) httpSession
                .getAttribute(SessionProperties.IN_SSH.value());
        out.write(bytes);
    }

    @OnClose
    public void onClose(Session session) throws IOException {
        if (session.isOpen()) {
            try {
                session.close();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

我有一个线程在socket打开时运行,但当用户重新加载时,我在输出中看不到Exiting OutputTask,这会在正常socket关闭时打印出来。该线程的代码

@Override
public void run() {
    InputStream stream = (StreamGobbler) session
            .getAttribute(SessionProperties.OUT_SSH.value());
    Basic basicRemote = (Basic) session
            .getAttribute(SessionProperties.BASIC_REMOTE.value());
    int read = 0;
    byte[] bt = new byte[1024];
    try {
        while (wsSession.isOpen() && (read = stream.read(bt)) != -1) {
            logger.info(new String(bt));
            basicRemote.sendText(new String(Arrays.copyOf(bt, read)));
            // TODO: Add logging and finalize code
        }
    } catch (SecurityException | IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        try {
            Handler[] handlers = logger.getHandlers();
            for (Handler h : handlers) {
                h.close();
            }
            logger = null;
            if (wsSession.isOpen()) {
                wsSession.close();
            }
            if (stream != null) {
                stream.close();
            }
            System.out.println("Exiting OutputTask");
            session.invalidate();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

用户重新加载页面时出错

java.lang.IllegalStateException: Message will not be sent because the WebSocket session has been closed
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:378)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessage(WsRemoteEndpointImplBase.java:335)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:264)
    at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:536)
    at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:464)
    at org.apache.tomcat.websocket.WsSession.close(WsSession.java:441)
    at org.apache.tomcat.websocket.WsSession.close(WsSession.java:435)
    at com.example.websocket.wss.onClose(WSSession.java:130)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.tomcat.websocket.pojo.PojoEndpointBase.onClose(PojoEndpointBase.java:107)
    at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:508)
    at org.apache.tomcat.websocket.WsSession.onClose(WsSession.java:491)
    at org.apache.tomcat.websocket.WsFrameBase.processDataControl(WsFrameBase.java:342)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:284)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:194)
    at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:95)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:653)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

共 (0) 个答案