javascript
Springboot整合Websocket遇到的坑_websocket session不支持序列化,无法存储至redis_Websocket相关问题总结(Session共享,用户多端登录等)
Springboot整合Websocket遇到的坑
一、使用Springboot內嵌的tomcat啟動websocket
1.添加ServerEndpointExporter配置bean
@Configuration public class WebSocketConfig {/*** 服務器節點** 如果使用獨立的servlet容器,而不是直接使用springboot的內置容器,就不要注入ServerEndpointExporter,因為它將由容器自己提供和管理* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}2.在接收連接的類加上@ServerEndpoint和@Component
@ServerEndpoint("/connect") @Component二、使用外部tomcat容器啟動websocket
1.刪除ServerEndpointExporter配置bean
2.接收連接的類刪除@Component
三、websocket關閉連接異常
如果客戶端關閉了websocket,但服務端沒有監聽到關閉事件,即onClose方法沒有調用,這是會發生的情況
此時如果服務端向客戶端推送消息,會出現異常告訴開發者:關閉了一個連接,并重新調用onClose方法
websocket 分布式開發,websocket session不支持序列化,無法存儲至redis
單websocket服務器在面對并發量很大時壓力會很大,而且session儲存在Map中,內存壓力也會很大。于是考慮分布式。
但是分布式存在websocket session共享問題,于是考慮radis存儲session,但是遇到websocket session不支持序列化,無法存儲。
一番搜索后有了以下幾個方案
使用spring session自定義session.
既然無法序列化session,那還是存儲在Map中,各服務器通過發布訂閱變相實現共享websocket session.
Websocket相關問題總結(Session共享,用戶多端登錄等)
我們在使用websocket的時候其實主要面對的問題就是session共享的問題:
不管是基于Spring實現的Websocket的WebsocketSession
還是基于JDK實現的Session
亦或者基于netty實現的ChannelHandlerContext
用圖來描述下場景吧:
OK,大家看到這個圖了,差不多應該明白了Session共享應該怎么處理了。其實原理很簡單:
1、我們知道nginx有IP保持的功能,其實這個功能就能解決大部分場景的Session共享問題。 但是某些極限情況下還是會有問題,比如在瀏覽器沒有關閉的情況下同一個用戶更換了網絡的情況導致IP變了,或者對于某些網絡的IP是變動的情況下,就會出現Session找不到的情況。
2、基于上述nginx的原理我們可以進行優化,還是單例存儲。那么要操作的時候,我告訴所有的服務端,你們去找這個用戶的Session,并把消息帶過去。那么相應的節點根據用戶拿到Session了就可以進行處理了。
上面2點大概簡單的描述了下Session共享的原理,那么有這么個場景,文字可能不太好表達,我們還是用圖來說明:
一般出現多端情況也應該就上面2種情況,要么允許,要么不允許。我這里簡單的說下不允許的處理流程。
建立連接的時候,先獲取老的Session
Session oldSession = SOCK_MAP.get(baseStudentInfo.getId());存在,則推送關閉消息,不存在告知其他節點去清楚。當然本節點的的Server要排除在外,這里就通過IP判斷即可。
if(oldSession!=null) {oldSession.getBasicRemote().sendObject(close);}else{//關閉其他節點的的sessionauthService.pushCloseMessage(close);}//替換SOCK_MAP.put(baseStudentInfo.getId(),session);消息監聽
String serverIp = IPUtils.getLocalhostIp();logger.info("當前IP:"+serverIp);logger.info("content的IP:"+wsMessage.getBody().getContent());//IP不相等,說明不是當前連接的服務端,關閉其他端口if(!serverIp.equals(wsMessage.getBody().getContent())){//關閉session,并返回給前端customerHandler.closeSession(wsMessage.getBody().getReceiver(), wsMessage);}關閉的方法:
/*** 關閉Session* @param studentId* @param closeMessage*/public void closeSession(Long studentId,WsMessage closeMessage){Session session = SOCK_MAP.get(studentId);if(session!=null) {try {session.getBasicRemote().sendObject(closeMessage);SOCK_MAP.remove(studentId);//清除redislogger.info("連接已關閉:" + studentId);} catch (Exception e) {e.printStackTrace();logger.error("關閉連接異常");}}}這樣基本就避免多端登錄的問題,如果允許多端登錄的時候只需要更改存儲,更改發送消息變成群發即可。
總結
以上是生活随笔為你收集整理的Springboot整合Websocket遇到的坑_websocket session不支持序列化,无法存储至redis_Websocket相关问题总结(Session共享,用户多端登录等)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【深度学习】卷积越大性能越强!RepLK
- 下一篇: qml 鼠标点击_QML ListVie