【问题标题】:Delayed disconnect mechanism for WebSocketsWebSockets 的延迟断开机制
【发布时间】:2015-04-14 16:21:29
【问题描述】:

我正在尝试向我正在开发的 WebSocket 聊天添加“延迟断开”机制。这意味着如果用户断开连接,但在某个时间限制内重新连接 - 我将使用 30 秒作为示例 - 断开连接将被忽略。这样做的原因是如果用户短暂失去连接的概念验证 - 例如。移动用户进入电梯。

我决定为此使用 cookie。我想通的逻辑是,当打开一个 WebSocket 时,它也会打开一个 HttpSession。由此,我可以检查是否存在具有特定 id 的 cookie。如果是这样,那么他们不会被视为新用户。但是,为此我需要能够将 cookie 的到期时间设置为 30 秒 套接字已关闭。

我已经知道Cookie.setMaxAge() 会这样做,但是当我在服务器上的 OnClose() 方法中尝试这个时,服务器抛出了 NullPointerException。这并不奇怪,因为我显然是在用户会话关闭后尝试访问它。

那么,有没有办法做到这一点?

2 月 16 日更新我决定在发送消息时尝试完全重置 cookie。这部分有效,因为 cookie 是生成并添加到 HttpSession 中的,但在重新连接服务器后,服务器会认为用户是全新的。所以,我认为我的问题是 cookie 没有发送给用户。

更新 2 阅读 this question 后,我将 cookie 生成移到了一个配置类中,该类在成功握手时调用。如果请求没有 cookie,它将被视为一个全新的连接,并将其记录到系统控制台作为概念证明。我必须做的一件事是在一开始就延长 cookie 的生命周期:目前,大概是 10 分钟。如果我不知道如何完全按照我上面所说的去做,我会继续这样做。

2 月 19 日更新我完全放弃了 cookie。请参阅我的解决方案。

【问题讨论】:

    标签: java cookies websocket reconnect


    【解决方案1】:

    我通过完全放弃 cookie 解决了这个问题。我刚刚展示了相关类中的方法;如果这还不够,我将编辑我的答案以包含完整的代码。

    在配置类中,我得到了请求的 x-forwarded-for 标头。这与客户端的 IP 地址相匹配,尤其是因为我的后端服务器位于代理后面。如果用户的 IP 地址在用户列表中,则他们的连接被“刷新”;否则,它们将被添加到列表中。在断开连接时,无论出于何种原因,用户都会被标记为断开连接。

    一个单独的ConnectionMonitor 类实现了Runnable 接口,每10 秒运行一次,并检查是否有任何客户端断开连接超过30 秒。如果是,则将它们从用户列表中删除。

    MyConfigClass.modifyHandshake()

    @Override
    public void modifyHandshake(ServerEndpointConfig config,
                                HandshakeRequest request,
                                HandshakeResponse response)
    {
        HttpSession theSession = (HttpSession) request.getHttpSession();
        config.getUserProperties().put(HttpSession.class.getName(), theSession);
    
        String ID = request.getHeaders().get("x-forwarded-for").get(0);
    
        if (ChatroomServerEndpoint.users.containsKey(ID))
        {
    
            // if this user isn't new, add them back onto the list
            User oldUser = ChatroomServerEndpoint.users.get(ID);
            System.out.println("An old user with " + ID + " has returned.");
            ChatroomServerEndpoint.users.remove(oldUser);
            ChatroomServerEndpoint.users.put(ID, oldUser);
            oldUser.toggleConnection(true);
            System.out.println(oldUser + ", " + ChatroomServerEndpoint.users.size() );
    
        }
        else
        {
            // add a new user to the list
            System.out.println("A new user with ID " + ID + " has arrived!");
            User newUser = new User(ID);
            ChatroomServerEndpoint.users.put(ID, newUser);
            System.out.println(newUser + ", " + ChatroomServerEndpoint.users.size() );
        }
    
        // put this ID into the configuration for proof of concept
        config.getUserProperties().put("newUser", ID);
    }
    

    ConnectionMonitor.updateUsers() 在单独的线程中运行。

    void updateUsers()
    {
    
        for(String id : ChatroomServerEndpoint.users.keySet())
        {
            User theUser = ChatroomServerEndpoint.users.get(id);
            if (theUser.getStatus() == User.Connection.DISCONNECTED)
            {
                // get the time at which the user disconnected
                Calendar disconnectDate = theUser.getdisconnectionDate();
    
                // Calendar.getTime.getTime returns milliseconds,
                // so, multiply maxDisconnectTime by 1000 to see if the user has expired
                if (theDate.getTime().getTime() - disconnectDate.getTime().getTime() 
                        >= maxDisconnectTime * 1000 )
                {
                    System.out.println(id + " has timed out");
                    ChatroomServerEndpoint.users.remove(id);
                }
            }
        }
    }
    

    用户

    public class User {
    
    
    // the ID is the user's IP address
    private String id;
    
    // connection status
    public enum Connection
    {
        CONNECTED,
        DISCONNECTED
    }
    
    private Connection status;
    
    // the time of disconnection
    private Calendar disconnectionDate;
    
    // each user needs a WebSocket Session to be able to send and receive messages
    private Session userSession;
    
    /** 
     * @return the id of this user
     */
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    /**
     * @return connection status
     */
    public Connection getStatus() {
        return status;
    }
    
    public void setStatus(Connection status) {
        this.status = status;
    }
    
    public Calendar getdisconnectionDate() {
        return disconnectionDate;
    }
    
    public void setdisconnectionDate(Calendar disconnectionDate) {
        this.disconnectionDate = disconnectionDate;
    }
    
    /**
     * @return the userSession
     */
    public Session getUserSession() {
        return userSession;
    }
    
    /**
     * @param userSession the userSession to set
     */
    public void setUserSession(Session userSession) {
        this.userSession = userSession;
    }
    
    /**
     * @param newID the new ID of the user
     */
    public User (String newID)
    {
        this.id = newID;
        this.status = Connection.CONNECTED;
    }
    
    /**
     * Toggles the connection
     * @param toggle - if true, the user is connected
     */
    public void toggleConnection(boolean toggle)
    {
        if (toggle == false)
        {
            status = Connection.DISCONNECTED;
            disconnectionDate = Calendar.getInstance();
        }
        else
        {
            status = Connection.CONNECTED;
            disconnectionDate = Calendar.getInstance();
            disconnectionDate.add(Calendar.HOUR, 1);        // give an extra hour to prevent them being disconnected too soon
    
        }
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 2023-02-14
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-20
      相关资源
      最近更新 更多