前言
众所周知,最近我在做物联网的项目,还不知道的话,可以看我这篇,
能帮我点个赞就更好了。
出现了个问题
服务端开启webSocket服务,前端通过new WebSocket(ws://ip:port/webSocket/aa)来连接。具体的就不赘述了,网上一搜一大把。
服务端拿到数据后,使用websocket传给前端
//给指定用户发送信息
public void sendInfo(String userName, String message){
Session session = sessionPools.get(userName);
try {
sendMessage(session, message);
}catch (Exception e){
e.printStackTrace();
}
}
前端的链接是www.xxxxx.com/iot。单个页面时,webSocket的连接、接收是正常的。但是,如果打开了多个页面,我惊奇的发现,只有最后一个打开的页面,接收到了webSocket消息,并且,在之前页面中socket的onerror和onclose都没有触发。然后我就查找webSocket服务代码。
//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value = "sid") String userName){
sessionPools.put(userName, session);
addOnlineCount();
}
原来是新连接上的页面session覆盖了之前key为userName的值。
找到了问题,那就好办了,只要把userName映射的值,从单个的session变成多个,然后在发送数据时,循环取出后发送消息。 1、创建一个List用来存放session。
private static List<Session> sessionList = Collections.synchronizedList(new ArrayList<>());
2、ConcurrentHashMap中存放Session的List
private static ConcurrentHashMap<String, List<Session>> sessionPools = new ConcurrentHashMap<>();
3、连接时,将客户端的session存入sessionList中
@OnOpen
public void onOpen(Session session, @PathParam(value = "sid") String userName){
sessionList.add(session);
sessionPools.put(userName, sessionList);
}
4、发送消息时,将session集取出
/**
* 给指定用户发送信息
* @param userName
* @param message
*/
public void sendInfo(String userName, String message){
sessionList = sessionPools.get(userName);
try {
if(sessionList != null && !sessionList.isEmpty()){
for(Session session:sessionList){
if(session.isOpen()){
sendMessage(session, message);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
5、当然,在客户端关闭连接时,要在sessionList中去掉
/**
* 关闭连接时调用
* @param userName
*/
@OnClose
public void onClose(Session session, @PathParam(value = "sid") String userName){
sessionList.remove(session);
subOnlineCount();
}
总结
最终是依靠客户端连接时的session来决定webSocket发送消息的方向来解决了这一问题。
webSocket在服务端和客户端传送消息时是比较常用的方法。在物联网项目中,如果服务端有安装mqtt的话,也可以选择mqtt订阅的模式比较方便。