【问题标题】:WebSocket: OnClose() is never calledWebSocket:永远不会调用 OnClose()
【发布时间】:2017-12-31 14:10:09
【问题描述】:

我正在实现一个带有 WebSocket 端点的应用程序。这是一些代码:

@ApplicationScoped
@ServerEndpoint(value="/socket", encoders = {MessageEncoder.class, CommandEncoder.class})
public class SocketEndpoint {

    /** Default-Logger */
    private final static Logger LOG = LoggerFactory.getLogger(SocketEndpoint.class);

    @Inject
    SessionHandler sessionHandler;

    @OnOpen
    public void open(Session session, EndpointConfig config) {
        LOG.debug("Connected session => '{}' - '{}'", session, config);
        sessionHandler.initSession(session);
    }

    @OnMessage
    public void onMessage(Session session, String messageJson) {
        // do something
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        LOG.debug("Closing session => '{}' - '{}'", session, reason);
        sessionHandler.removeSession(session);
    }

    @OnError
    public void onError(Session session, Throwable ex) { 
        LOG.error("WebSocket error => '{}'", ex.getMessage()); 
    }
}

其中一个编码类如下所示:

public class MessageEncoder implements Encoder.Text<Message> {

    /** Default-Logger */
    private final static Logger LOG = LoggerFactory.getLogger(MessageEncoder.class);

    @Override
    public void init(EndpointConfig config) {
        LOG.debug("Init MessageEncoder");
    }

    @Override
    public void destroy() {
        LOG.debug("Destroy MessageEncoder");
    }

    @Override
    public String encode(MessageE message) throws EncodeException {
        return message.toString();
    }
}

按预期打开 WebSocket 调用 SocketEndpoint.open()。 关闭 WebSocket 只调用MessageEncoder.destroy() 而不是SocketEndpoint.close()

谁能给我一个建议,我做错了什么?如果没有解决方案,我将不得不手动检查注册的会话是否仍然存在,因为MessageEncoder.destroy() 没有参数。

提前致谢!


更新

刚刚实现了一个虚拟端点:

@ApplicationScoped
@ServerEndpoint("/dummy")
public class DummyEndpoint {

    /** Default-Logger */
    private final static Logger LOG = LoggerFactory.getLogger(DummyEndpoint.class);

    @OnOpen
    public void open(Session session, EndpointConfig config) {
        LOG.debug("Connected session with principal => '{}'", session.getId());
    }

    @OnMessage
    public void onMessage(Session session, String messageJson) {
        LOG.debug("on message => '{}' => '{}'", session.getId(), messageJson); 
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        LOG.debug("Closing session => '{}' - '{}'", session, reason);
    }

    @OnError
    public void onError(Session session, Throwable ex) { 
        LOG.error("WebSocket error => '{}' => '{}'", session, ex.getMessage()); 
    }
}

当使用这个虚拟端点时,@OnClose 被正确调用。我只能看到 SocketEndpoint 类的一个主要区别:DummyEndpoint 不使用任何 Encoder 类。

有什么提示吗?

【问题讨论】:

  • 您使用的是什么应用服务器?当你说关闭 WebSocket 时,你到底是什么意思?您是从调用 websocket.close() 的客户端 vi 关闭它吗?还是关闭浏览器?
  • 我使用的是 Wildfly 10.0.1 应用服务器。尝试关闭 websocket 调用 ws.close() 并关闭浏览器。
  • 可能与以下内容重复:stackoverflow.com/questions/24717403/…
  • @Duong Nguyen 这不是重复的。在发这个之前看到你的意思的帖子。我使用 Firefox、Chrom、IE、Edge 和一些用于 Websockets 的 FF/Chrome 插件测试了我的代码……此外:我实现的“@OnError”方法也没有被调用。关闭 websocket 时调用的唯一方法是编码器类中的“@OnDestroy”。
  • 使用此quickstart 并添加OnClose 注释,在关闭选项卡时调用该方法。我使用wildfly 10.1.0.Final,Java 8。您在端点中使用的SessionHandler 是什么?

标签: java websocket encoder oncloselistener


【解决方案1】:

正如 cmets 中所述,代码运行良好。如果我们从这个wildfly-websocket-quickstart 开始,在ServerEndpoint 上添加一个@OnClose 修饰方法,它可以在Wildfly 10.x 和最近的浏览器(例如Chrome v59.x)上正常工作。在这里工作的 ServerEndpoint 示例(使用 @Inject 不要忘记在 WEB-INF 文件夹中添加 beans.xml):

@ApplicationScoped
@ServerEndpoint(value="/shout", encoders = {MessageEncoder.class})
public class ShoutServerEndpoint {

    @Inject
    SessionHandler s;

    @OnOpen
    public void open(Session session, EndpointConfig config) throws Exception {
        s.initSession(session);
    }

    @OnMessage
    public void shout(String text, Session client) {
        System.out.println("Session: " + client + " has text: " + text);
        Message m = new Message();
        try {
            client.getBasicRemote().sendObject(m);//use the encoder to write some dummy message
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (EncodeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        client.getAsyncRemote().sendText(text.toUpperCase());
    }


    @OnClose
    public void onClose(Session client, CloseReason reason){
        System.out.println("Session " + client + " closing for " + reason);
        s.destroySession(client);

    }

    @OnError
    public void onError(Session session, Throwable ex) { 
        System.out.println("error: " + ex.getMessage() );
    }
}

因此,罪魁祸首似乎是 Wildfly 使用的旧版本代码在重新部署 webapp 期间没有被清理,例如,使用 Eclipse,在出现奇怪行为的情况下使用 @ 是值得的所用服务器上的 987654329@ 选项(请参阅:this Eclipse doc

如果直接使用 wildfly 部署,您可以通过删除 (from this article) 中的所有内容来清理资源:

  • /[wildfly-location]/standalone/data
  • /[wildfly-location]/standalone/deployments
  • /[wildfly-location]/standalone/tmp

它确保在未来部署期间不会保留旧代码副本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-15
    • 2014-11-01
    • 2016-07-22
    • 1970-01-01
    • 2021-02-01
    • 1970-01-01
    • 2020-11-18
    • 2012-10-27
    相关资源
    最近更新 更多