Websocket服务器:处理每个会话的关闭事件

时间:2017-09-21 10:09:31

标签: java java-ee websocket

有没有办法处理每个会话的websocket的服务器端关闭事件?这就是我目前的实现方式:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Websocket opened");
        CustomWebsocketHandler handler = new CustomWebsocketHandler(session); // see below
        // ...
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("Websocket closed. Reason: " + reason);
    }
}

但我想在自定义对象中包装新的Session实例。对于消息,我可以通过addMessageHandler将处理程序直接添加到特定会话。但是如何在该特定会话中为onClose事件添加处理程序?:

class CustomWebsocketHandler {
    public CustomWebsocketHandler(Session session) {
        session.addMessageHandler((MessageHandler.Whole<String>) this::handleMessage);
        // How to hook up close event to handleClose()?
    }

    private void handleMessage(String message) { /* ... */ }

    private void handleClose() { /* ... */ }
}

我的一个想法是跟踪WebsocketServerEndpoint及其各自的CustomWebsocketHandler实例中的每个会话,并针对每个关闭事件检查它们,转发事件。然而,这非常麻烦并且容易出错:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    private List<Pair<Session, CustomWebsocketHandler>> sessions = new ArrayList<>();

    @OnOpen
    public void onOpen(Session session) {
        // ...
        sessions.add(Pair.of(session, handler)); // not hashable I suppose
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        // ...
        for (Iterator<Pair<Session, CustomWebsocketHandler>> it = sessions.iterator(); it.hasNext(); ) {
            Pair<Session, CustomWebsocketHandler> pair = it.next();
            if (pair.getLeft() == session) {
                pair.getRight().handleClose();
                it.remove();
                break;
            }
        }
    }
}

在客户端这很容易,因为每个连接都可以使用自己的ClientEndpoint实例 - 带注释的类:

webSocketContainer.connectToServer(endpointInstance, websocketURI);

服务器端是否存在类似的情况,或者是否可以完全处理每个会话的服务器端onClose(最终还是onError)事件?

1 个答案:

答案 0 :(得分:0)

默认情况下,为每个新客户端创建ServerEndpoint - 带注释的类的新实例。此行为由ServerEndpointConfig.Configurator#getEndpointInstance方法控制:

  

此方法的平台默认实现为每个调用返回一个新的端点实例,从而确保每个客户端有一个端点实例,即默认的部署基数。

这意味着在WebsocketServerEndpoint类本身中存储特定于会话的状态是安全的,而不必手动将会话与自定义连接实例关联:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    private CustomWebsocketHandler handler;

    @OnOpen
    public void onOpen(Session session) {
        handler = new CustomWebsocketHandler(session);
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        handler.handleClose();
    }
}

此时,让注释类WebsocketServerEndpoint本身需要CustomWebsocketHandler也可能更容易,因为它具有相同的语义:每个连接一个实例并处理websocket事件。