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

Posted

技术标签:

【中文标题】Websocket服务器:每个会话处理关闭事件【英文标题】:Websocket server: Handle close event per session 【发布时间】:2017-09-21 10:09:31 【问题描述】:

有没有办法处理每个会话的 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-annotated 类实例:

webSocketContainer.connectToServer(endpointInstance, websocketURI);

服务器端是否存在类似的东西,或者是否可以干净地处理每个会话的服务器端onClose(最终还有onError)事件?

【问题讨论】:

【参考方案1】:

默认情况下,会为每个新客户端创建一个 ServerEndpoint-annotated 类的新实例。此行为由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 事件。

【讨论】:

以上是关于Websocket服务器:每个会话处理关闭事件的主要内容,如果未能解决你的问题,请参考以下文章

为多个主机上的 PHP 站点处理会话的最佳方法是啥? [关闭]

触发 websocket 错误事件

初识Websocket

关闭连接到 Mojo websocket 的 Mojo::IOLoop 重复事件

在spring中获取websocket会话的关联HTTPSession

实现 Core Audio API 事件