如何知道客户端何时停止ping Java服务器?

时间:2012-07-20 19:03:35

标签: java servlets client-server embedded-jetty

我决定让我的客户定期“ping”服务器,以便我知道客户端仍然存在。我正在使用嵌入在Java应用程序中的Jetty服务器,我有一个HttpServlet来处理客户端请求。

在服务器端,我怎么知道客户端什么时候没有“ping”(发送请求)?

5 个答案:

答案 0 :(得分:2)

通过其sessionID识别客户端,并跟踪上次ping。定期扫描所有最后一次ping,找到那些没有在N分钟内进行ping操作的人。

答案 1 :(得分:2)

扩展srini.venigalla的答案,你可以使用这样的东西作为起点。

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.*;

public class PingServlet extends HttpServlet {
    private static final long EXPIRATION_MILLIS = TimeUnit.SECONDS.toMillis(30);

    private final ConcurrentMap<String, Long> sessionIdToLastPingTime = new ConcurrentHashMap<String, Long>();
    private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    public void init() {
        executor.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                scanForExpiredSessions();
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    private void scanForExpiredSessions() {
        for (Map.Entry<String, Long> entry : sessionIdToLastPingTime.entrySet()) {
            if (Thread.currentThread().isInterrupted()) {
                return;
            }

            final String sessionId = entry.getKey();
            final Long lastPing = entry.getValue();
            if (lastPing == null) {
                // entry was removed from the map by another thread
                continue;
            }
            if (System.currentTimeMillis() > lastPing + EXPIRATION_MILLIS) {
                sessionIdToLastPingTime.remove(sessionId);
                try {
                    expireSession(sessionId);
                } catch (Exception e) {
                    // production code should use a logger
                    e.printStackTrace();
                }
            }
        }
    }

    private void expireSession(String sessionId) {
        // production code should use a logger
        System.out.println("client stopped pinging for session " + sessionId);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        String sessionId = req.getSession().getId();
        sessionIdToLastPingTime.put(sessionId, System.currentTimeMillis());
    }

    @Override
    public void destroy() {
        executor.shutdownNow();

        try {
            // this is optional, but may prevent Tomcat from reporting the webapp as a memory-leaker
            executor.awaitTermination(3, TimeUnit.SECONDS);
        } catch (InterruptedException e) {                                                                          
            // production code should use a logger
            System.out.println("interrupted while waiting for executor to shut down");
            Thread.currentThread().interrupt();
        }
    }
}

答案 2 :(得分:0)

琐碎的案例:

  1. 告诉客户端每N秒ping一次
  2. 保留上次客户端ping通时间的时间戳,更新每次客户端ping后的时间戳
  3. 如果此时间戳明显大于N秒,则客户端已停止ping(至少目前为止)

答案 3 :(得分:0)

在服务器端,您可以使用java Date类在上次收到ping时存储。

long lastRecv = System.getTimeMillis();

在另一个循环中(可能是另一个定期检查所有已知客户端数组的线程),您将检查lastRecv时间码并立即将其与之比较。

if( date.getTime() - lastRecv > TIMEOUT_IN_MS )
    // Handle user timing out

每次收到新的ping时,只需将lastRecv时间更新为新的当前时间。您将知道用户何时超时,因为您有一些预设阈值(例如TIMEOUT_IN_MS)小于您上次看到ping进入的时间。

显然,你必须修改我在这里提供的示例代码,以反映客户端数量,线程模型和数据模型,但我认为它足以满足这个想法。

答案 4 :(得分:0)

也许使用会话超时较短的HttpSessionListener?

http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpSessionListener.html