Jetty 中 WebSocketListener 的轻量级 IPC
Lightweight IPC to WebSocketListener in Jetty
Android、iOS 和桌面浏览器客户端目前每隔几秒轮询一个 PHP-后端(利用 CentOS Linux 上的 PostgreSQL 数据库)。
我想通过使用独立 Jetty Websocket Server 来通知客户新数据可用于在后端获取。
所以在自定义 WebSocketListener
中,我对连接的客户端进行身份验证并将它们存储在 ConcurrentHashMap<String,Session>
:
public class MyListener implements WebSocketListener
{
private Session mSession;
@Override
public void onWebSocketConnect(Session session) {
mSession = session;
}
@Override
public void onWebSocketText(String message) {
if (mSession != null && mSession.isOpen()) {
// 1. validate client id and password
// 2. store client id and session into Map
}
}
我的问题:如何通知已连接(通过 websockets)的客户端?
即在 PHP-scripts 中,我想 运行 一个轻量级程序 java -jar MyNotify.jar client-1234
来告诉 Jetty 独立服务器:
Hey, there is new data available for the client-1234
at the database!
Please send it a short message over websockets by calling
MyMap.get("client-1234").getRemote().sendString("hey", null);
你必须把你的
ConcurrentHashMap<String,Session> sessionMap.
进入自定义 javax.servlet.ServletContextEvent 上的 public 静态字段。应在事件
上初始化字段
@Override
public void contextInitialized(ServletContextEvent ctx) {
然后在您应用程序的任何位置,您都可以以正常方式(使用点语法)访问此静态字段。
因为 contextInitialized 在任何 servlet 或 websockets 方法(get、put、onMessage)之前触发,所以 map 将在那里。同样是concurrent map,里面应该没有重复的id。
当然,您还需要清理会话映射的策略。总而言之,您必须与来自 javax.servlet API.
的事件一起构建您的系统
类似例子:
package example;
import java.io.FileNotFoundException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.*;
/**
* Application lifecycle events. Handles:
* <ul>
* <li>start, shutdown of application
* <li>start, stop of session
* </ul>
*
* @author mitjag
*
*/
public class AppInit implements HttpSessionListener, ServletContextListener {
public static final Logger log = Logger.getLogger(AppInit.class.getCanonicalName());
public static final Map<String, HttpSession> SESSION_MAP = new ConcurrentHashMap<String, HttpSession>(); /* access AppInit.SESSION_MAP from anywhere in your app*/
@Override
public void contextInitialized(ServletContextEvent ctx) {}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
// With this trick we maintain the list of sessionid's together with corresponding session
// It is used to grab the session if you have the valid session id
final String sid = arg0.getSession().getId();
log.info("SESSION CREATED with id " + arg0.getSession().getId());
SESSION_MAP.put(sid, arg0.getSession());
}
/**
* Called on session invalidation (manual or session timeout trigger, defined in web.xml (session-timeout)).
* @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
*/
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
// remove session from our list (see method: sessionCreated)
final String sid = arg0.getSession().getId();
SESSION_MAP.remove(sid);
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
}
Android、iOS 和桌面浏览器客户端目前每隔几秒轮询一个 PHP-后端(利用 CentOS Linux 上的 PostgreSQL 数据库)。
我想通过使用独立 Jetty Websocket Server 来通知客户新数据可用于在后端获取。
所以在自定义 WebSocketListener
中,我对连接的客户端进行身份验证并将它们存储在 ConcurrentHashMap<String,Session>
:
public class MyListener implements WebSocketListener
{
private Session mSession;
@Override
public void onWebSocketConnect(Session session) {
mSession = session;
}
@Override
public void onWebSocketText(String message) {
if (mSession != null && mSession.isOpen()) {
// 1. validate client id and password
// 2. store client id and session into Map
}
}
我的问题:如何通知已连接(通过 websockets)的客户端?
即在 PHP-scripts 中,我想 运行 一个轻量级程序 java -jar MyNotify.jar client-1234
来告诉 Jetty 独立服务器:
Hey, there is new data available for the
client-1234
at the database!Please send it a short message over websockets by calling
MyMap.get("client-1234").getRemote().sendString("hey", null);
你必须把你的
ConcurrentHashMap<String,Session> sessionMap.
进入自定义 javax.servlet.ServletContextEvent 上的 public 静态字段。应在事件
上初始化字段 @Override
public void contextInitialized(ServletContextEvent ctx) {
然后在您应用程序的任何位置,您都可以以正常方式(使用点语法)访问此静态字段。
因为 contextInitialized 在任何 servlet 或 websockets 方法(get、put、onMessage)之前触发,所以 map 将在那里。同样是concurrent map,里面应该没有重复的id。
当然,您还需要清理会话映射的策略。总而言之,您必须与来自 javax.servlet API.
的事件一起构建您的系统类似例子:
package example;
import java.io.FileNotFoundException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.*;
/**
* Application lifecycle events. Handles:
* <ul>
* <li>start, shutdown of application
* <li>start, stop of session
* </ul>
*
* @author mitjag
*
*/
public class AppInit implements HttpSessionListener, ServletContextListener {
public static final Logger log = Logger.getLogger(AppInit.class.getCanonicalName());
public static final Map<String, HttpSession> SESSION_MAP = new ConcurrentHashMap<String, HttpSession>(); /* access AppInit.SESSION_MAP from anywhere in your app*/
@Override
public void contextInitialized(ServletContextEvent ctx) {}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
// With this trick we maintain the list of sessionid's together with corresponding session
// It is used to grab the session if you have the valid session id
final String sid = arg0.getSession().getId();
log.info("SESSION CREATED with id " + arg0.getSession().getId());
SESSION_MAP.put(sid, arg0.getSession());
}
/**
* Called on session invalidation (manual or session timeout trigger, defined in web.xml (session-timeout)).
* @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
*/
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
// remove session from our list (see method: sessionCreated)
final String sid = arg0.getSession().getId();
SESSION_MAP.remove(sid);
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
}