How to properly close the server side websocket session when the user reloads the web page and the websocket session time?

java.lang.IllegalStateExceptionwhen the user reloads the page. The method is called onClose. I get an exception that the socket is already closed. Because of this, I cannot clear a few things in another thread that stops when the web socket session closes. Everything is in order if the user closes the session without reloading the page (basically this is the server terminal via websocket). I am on tomcat8.

Questions.

  • How to properly close a websocket session on the server if the user reloads the page?
  • Also, how can I do a few things when the webshocket session time ends?

Below is the code that serves the connection to the web server.

@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();
            }
        }
    }
}

, , , , Exiting OutputTask , . .

@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)
+4

Source: https://habr.com/ru/post/1568192/


All Articles