如何正确关闭Java-EE WebSocket连接

6

我正在使用Java-EE WebSockets实现一个小型聊天应用程序。
有时候我需要出于各种原因关闭客户端的会话以关闭连接。
为了关闭连接,我调用了onClose函数,在该函数中我调用了session.close(),但之后我得到了以下错误:

java.lang.IllegalStateException: The WebSocket session has been closed and no method (apart from close()) may be called on a closed session
    at org.apache.tomcat.websocket.WsSession.checkState(WsSession.java:643)
    at org.apache.tomcat.websocket.WsSession.addMessageHandler(WsSession.java:168)
    at org.apache.tomcat.websocket.pojo.PojoEndpointBase.doOnOpen(PojoEndpointBase.java:81)
    at org.apache.tomcat.websocket.pojo.PojoEndpointServer.onOpen(PojoEndpointServer.java:70)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init(WsHttpUpgradeHandler.java:129)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:629)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

我不确定自己做错了什么,也不知道为何出现了这个异常。


已经过去一年了..你找出问题所在并学会如何正确处理了吗?我现在在Tomcat7上遇到了同样的问题。 - TMG
4个回答

3
我今天学习这方面的内容时遇到了同样的问题。目前我所发现的是,在服务器上的注释@OnMessage中,当服务器接收到“quit”消息时,我通过调用session.close来关闭连接。 然后在@OnMessage的结尾处,我发出了必须的返回,因为该方法需要返回,而正是这个返回导致了异常,因为会话已经被关闭了。 我的解决方案是,不让服务器关闭会话,而是向客户端发送一个“youquit”消息,然后让客户端调用session.close。 现在,服务器接收到关闭事件,并准备好下一个连接,客户端也没有异常地结束了。
@OnMessage
public String onMessage(String message, Session session) throws DeploymentException, IOException {
    switch (message) {
        case "quit":
            //session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE, "Game ended"));
            message = "you" + message;
            break;
    }
    return message;
}

@OnClose
public void onClose(Session session, CloseReason closeReason) {
    logger.info(String.format("Session %s closed because of %s", session.getId(), closeReason));
}

我曾尝试在返回级别捕获异常,但它并没有起作用。

我现在相信,在@OnMessage入口点无法关闭连接。


1

我认为这在这种情况下不相关。原帖作者似乎直接使用JSR356 Websocket API,而不是通过Atmosphere框架。 - TMG

0

检查会话是否已打开,如果是,则关闭它。

if(session.isOpen()){
    session.close();
}

0

当会话关闭时,Websocket OnClose 方法被调用,您不需要关闭会话。您想要关闭已经关闭的会话,这个错误显示会话已经关闭。您可以从这里看到:

http://docs.oracle.com/javaee/7/api/javax/websocket/Session.html

一旦会话关闭,它就不再适用于应用程序。在会话关闭后调用其任何方法(除了close()方法)将导致抛出IllegalStateException异常。开发人员应该在Endpoint.onClose(javax.websocket.Session, javax.websocket.CloseReason)方法中检索会话的任何信息。按照Closeable的约定,在会话关闭后调用Session close()方法没有任何效果。

正如 blockquote 所说:“一旦已关闭会话,调用其任何方法(close() 方法除外)都将导致抛出 IllegalStateException”,但是在调用 session.close() 时却抛出了 IllegalStateException。 - Dheerendra
你确定在会话关闭后不会调用其他方法吗?你调试过项目了吗? - Anar Orujov
1
我想做的就是从服务器端强制关闭会话,这就是我调用session.close()的原因。 - Dheerendra
当客户端被中断时,在至少Tomcat 9和可能许多其他服务器上,服务器上没有OnClose触发器。如果客户端结束连接,则会抛出EndOfFile错误。我在OnError中捕获它并在那里关闭连接。 - Vincent Gerris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接