个人网站例子,大连工程预算服务,semiconductor,wordpress 443端口适用于单客户端#xff0c;一个账号登陆一个客户端#xff0c;登陆多个客户端会报错
The remote endpoint was in state [TEXT_FULL_WRITING]
这是因为此时的session是不同的#xff0c;只能锁住一个session#xff0c;解决此问题的方法把全局静态对象锁住#xff0c;因…适用于单客户端一个账号登陆一个客户端登陆多个客户端会报错
The remote endpoint was in state [TEXT_FULL_WRITING]
这是因为此时的session是不同的只能锁住一个session解决此问题的方法把全局静态对象锁住因为账号是唯一的 /*** Description 开启springboot对websocket的支持* Author WangKun* Date 2023/8/14 17:21* Version*/
ConditionalOnProperty(name spring.profiles.active, havingValue dev)
Configuration
public class WebSocketConfig{/*** Description 注入一个ServerEndpointExporter, 会自动注册使用ServerEndpoint注解* param* Throws* Return org.springframework.web.socket.server.standard.ServerEndpointExporter* Date 2023-08-14 17:26:31* Author WangKun*/Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}/*** Description websocket服务不考虑分组* Author WangKun* Date 2023/8/14 17:29* Version*/
ConditionalOnClass(value WebSocketConfig.class)
ServerEndpoint(/websocket/{userId})
Component
Slf4j
public class WebSocket {private static final long SESSION_TIMEOUT 60000;//存放每个客户端对应的WebSocket对象。private static final ConcurrentHashMapString, CopyOnWriteArraySetWebSocket WEB_SOCKET_MAP new ConcurrentHashMap();//与某个客户端的连接会话需要通过它来给客户端发送数据private Session session;private String userId;/*** param o* Description 重写防止session重复* Throws* Return boolean* Date 2023-09-01 10:02:51* Author WangKun*/Overridepublic boolean equals(Object o) {if (this o) {return true;}if (o null || getClass() ! o.getClass()) {return false;}WebSocket that (WebSocket) o;return Objects.equals(session, that.session);}Overridepublic int hashCode() {return Objects.hash(session);}/*** param session* param userId* Description 建立连接* Throws* Return void* Date 2023-08-14 17:52:08* Author WangKun*/SneakyThrowsOnOpenpublic void onOpen(final Session session, PathParam(userId) String userId) {this.session session;this.userId userId;session.setMaxIdleTimeout(SESSION_TIMEOUT);//先查找是否有uniCodeCopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(userId);if (users null) {//处理多个同时连接并发synchronized (WEB_SOCKET_MAP) {if (!WEB_SOCKET_MAP.contains(userId)) {users new CopyOnWriteArraySet();WEB_SOCKET_MAP.put(userId, users);}}}users.add(this);sendMessage(String.valueOf(ResponseCode.CONNECT_SUCCESS.getCode()));log.info(用户---{} 连接成功,当前在线人数为---{}, userId, WEB_SOCKET_MAP.size());}/*** param message* Description 向客户端发送消息 session.getBasicRemote()与session.getAsyncRemote()的区别* Throws* Return void* Date 2023-08-14 17:51:07* Author WangKun*/SneakyThrowspublic void sendMessage(String message) {// 加锁避免阻塞// 如果有多个客户端的话亦或者同一个用户或者打开了多个浏览器同一个用户打开多个客户端或者多个界面开了多个页面,此时Session是不同的,只能锁住一个session,所以锁住全局静态对象
// synchronized(session) {
// this.session.getBasicRemote().sendText(message);
// }synchronized (WEB_SOCKET_MAP) {CopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(userId);if (users ! null) {for (WebSocket user : users) {// 判断当前客户端的用户是否打开连接if (user.session.isOpen()) {user.session.getBasicRemote().sendText(message);log.info(向客户端发送数据---{} 数据为---{}, userId, message);}}}}}/*** param* Description 关闭连接* Throws* Return void* Date 2023-08-14 17:52:30* Author WangKun*/SneakyThrowsOnClosepublic void onClose(Session session) {// 避免多人同时在线直接关闭通道。CopyOnWriteArraySetWebSocket copyOnWriteArraySet WEB_SOCKET_MAP.get(this.userId);if (!copyOnWriteArraySet.isEmpty()) {Object[] objects copyOnWriteArraySet.toArray();for (Object object : objects) {if (((WebSocket) object).session.equals(session)) {//删除当前用户WEB_SOCKET_MAP.get(this.userId).remove((WebSocket) object);// 如果有一个客户端登陆 下线清除用户if (WEB_SOCKET_MAP.get(this.userId).isEmpty()) {WEB_SOCKET_MAP.remove(this.userId);}CloseReason close new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, 关闭客户端下线);session.close(close);log.info(用户---{} 关闭连接, userId);}}}}/*** param message* param session* Description 收到客户端消息* Throws* Return void* Date 2023-08-15 10:54:55* Author WangKun*/SneakyThrowsOnMessagepublic void onMessage(String message, Session session) {//枷锁避免多个资源互抢//这一块可以操作数据比如存到数据// 同一个用户多个地方登录多个session循环发送消息,// 如果有多个客户端的话亦或者同一个用户或者打开了多个浏览器开了多个页面,此时Session是不同的,只能锁住一个session,所以锁住全局静态对象synchronized (WEB_SOCKET_MAP) {CopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(userId);if (users ! null) {for (WebSocket user : users) {if (user.session.isOpen()) {user.session.getBasicRemote().sendText(pong);log.info(收到客户端发送的心跳的数据---{} 数据为---{}, userId, message);}}}}}/*** param session* param error* Description 发生错误时* Throws* Return void* Date 2023-08-15 10:55:27* Author WangKun*/SneakyThrowsOnErrorpublic void onError(Session session, Throwable error) {CopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(userId);if (!users.isEmpty()) {Object[] objects users.toArray();for (Object object : objects) {if (((WebSocket) object).session.equals(session)) {//删除当前用户WEB_SOCKET_MAP.get(this.userId).remove((WebSocket) object);// 如果有一个客户端登陆 下线清除用户if (WEB_SOCKET_MAP.get(this.userId).isEmpty()) {WEB_SOCKET_MAP.remove(this.userId);}CloseReason close new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, 异常下线);session.close(close);log.error(用户---{} 错误 userId, 原因---{} error.getMessage(), error);}}}
// WEB_SOCKET_MAP.remove(userId);
// log.error(用户---{} 错误 userId, 原因---{} error.getMessage(), error);}/*** param userId* param message* Description 通过userId向客户端发送消息指定用户发送* Throws* Return void* Date 2023-08-14 18:01:35* Author WangKun*/public static void sendTextMessageByUserId(String userId, String message) {CopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(userId);if (users ! null) {for (WebSocket user : users) {user.sendMessage(message);log.info(服务端发送消息到用户{},消息{}, userId, message);}}}/*** param message* Description 群发自定义消息* Throws* Return void* Date 2023-08-14 18:03:38* Author WangKun*/public static void sendTextMessage(String message) {// 如果在线一个就广播if (!WEB_SOCKET_MAP.isEmpty()) {for (String item : WEB_SOCKET_MAP.keySet()) {CopyOnWriteArraySetWebSocket users WEB_SOCKET_MAP.get(item);if (users ! null) {for (WebSocket user : users) {user.sendMessage(message);log.info(服务端发送消息到用户{},消息{}, item, message);}}}}}
} 文章转载自: http://www.morning.ykshx.cn.gov.cn.ykshx.cn http://www.morning.cnprt.cn.gov.cn.cnprt.cn http://www.morning.zydr.cn.gov.cn.zydr.cn http://www.morning.pqjpw.cn.gov.cn.pqjpw.cn http://www.morning.ckctj.cn.gov.cn.ckctj.cn http://www.morning.mtsgx.cn.gov.cn.mtsgx.cn http://www.morning.ndxrm.cn.gov.cn.ndxrm.cn http://www.morning.tmfhx.cn.gov.cn.tmfhx.cn http://www.morning.xnrgb.cn.gov.cn.xnrgb.cn http://www.morning.nrfrd.cn.gov.cn.nrfrd.cn http://www.morning.txtgy.cn.gov.cn.txtgy.cn http://www.morning.gyzfp.cn.gov.cn.gyzfp.cn http://www.morning.rqkk.cn.gov.cn.rqkk.cn http://www.morning.hdrsr.cn.gov.cn.hdrsr.cn http://www.morning.dqxnd.cn.gov.cn.dqxnd.cn http://www.morning.hhboyus.cn.gov.cn.hhboyus.cn http://www.morning.ycmpk.cn.gov.cn.ycmpk.cn http://www.morning.ycpnm.cn.gov.cn.ycpnm.cn http://www.morning.drnjn.cn.gov.cn.drnjn.cn http://www.morning.mnmrx.cn.gov.cn.mnmrx.cn http://www.morning.krnzm.cn.gov.cn.krnzm.cn http://www.morning.fbmjw.cn.gov.cn.fbmjw.cn http://www.morning.fpkdd.cn.gov.cn.fpkdd.cn http://www.morning.kngqd.cn.gov.cn.kngqd.cn http://www.morning.cxryx.cn.gov.cn.cxryx.cn http://www.morning.gllgf.cn.gov.cn.gllgf.cn http://www.morning.ryzgp.cn.gov.cn.ryzgp.cn http://www.morning.dnqlba.cn.gov.cn.dnqlba.cn http://www.morning.tpyjr.cn.gov.cn.tpyjr.cn http://www.morning.bnrnb.cn.gov.cn.bnrnb.cn http://www.morning.tgwfn.cn.gov.cn.tgwfn.cn http://www.morning.wztlr.cn.gov.cn.wztlr.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.wmfh.cn.gov.cn.wmfh.cn http://www.morning.nshhf.cn.gov.cn.nshhf.cn http://www.morning.kbqbx.cn.gov.cn.kbqbx.cn http://www.morning.lyhrg.cn.gov.cn.lyhrg.cn http://www.morning.lmfxq.cn.gov.cn.lmfxq.cn http://www.morning.tjkth.cn.gov.cn.tjkth.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.txrq.cn.gov.cn.txrq.cn http://www.morning.btlsb.cn.gov.cn.btlsb.cn http://www.morning.bwjws.cn.gov.cn.bwjws.cn http://www.morning.wnzgm.cn.gov.cn.wnzgm.cn http://www.morning.tqsmg.cn.gov.cn.tqsmg.cn http://www.morning.dmtbs.cn.gov.cn.dmtbs.cn http://www.morning.qwdlj.cn.gov.cn.qwdlj.cn http://www.morning.wfbnp.cn.gov.cn.wfbnp.cn http://www.morning.bnjnp.cn.gov.cn.bnjnp.cn http://www.morning.mdfxn.cn.gov.cn.mdfxn.cn http://www.morning.dpqqg.cn.gov.cn.dpqqg.cn http://www.morning.pylpd.cn.gov.cn.pylpd.cn http://www.morning.pzjfz.cn.gov.cn.pzjfz.cn http://www.morning.kqgsn.cn.gov.cn.kqgsn.cn http://www.morning.rwrn.cn.gov.cn.rwrn.cn http://www.morning.hmqwn.cn.gov.cn.hmqwn.cn http://www.morning.bydpr.cn.gov.cn.bydpr.cn http://www.morning.xbdrc.cn.gov.cn.xbdrc.cn http://www.morning.lnmby.cn.gov.cn.lnmby.cn http://www.morning.lwmzp.cn.gov.cn.lwmzp.cn http://www.morning.rpkg.cn.gov.cn.rpkg.cn http://www.morning.tsgxz.cn.gov.cn.tsgxz.cn http://www.morning.ylljn.cn.gov.cn.ylljn.cn http://www.morning.rbylq.cn.gov.cn.rbylq.cn http://www.morning.btnmj.cn.gov.cn.btnmj.cn http://www.morning.ljmbd.cn.gov.cn.ljmbd.cn http://www.morning.gfznl.cn.gov.cn.gfznl.cn http://www.morning.hwbmn.cn.gov.cn.hwbmn.cn http://www.morning.ptslx.cn.gov.cn.ptslx.cn http://www.morning.qfgwx.cn.gov.cn.qfgwx.cn http://www.morning.rcgzg.cn.gov.cn.rcgzg.cn http://www.morning.bpmfl.cn.gov.cn.bpmfl.cn http://www.morning.jwwfk.cn.gov.cn.jwwfk.cn http://www.morning.rfrx.cn.gov.cn.rfrx.cn http://www.morning.lzqtn.cn.gov.cn.lzqtn.cn http://www.morning.xkqjw.cn.gov.cn.xkqjw.cn http://www.morning.tkgxg.cn.gov.cn.tkgxg.cn http://www.morning.jyjqh.cn.gov.cn.jyjqh.cn http://www.morning.wgbmj.cn.gov.cn.wgbmj.cn http://www.morning.xllrf.cn.gov.cn.xllrf.cn