WebSockets的延迟断开机制

时间:2015-02-13 15:18:57

标签: java cookies websocket reconnect

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

我决定使用cookies。我发现的逻辑是,当打开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。见我的解决方案。

1 个答案:

答案 0 :(得分:0)

我通过完全抛弃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

    }
}

}