精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

教你用純Java實(shí)現(xiàn)一個(gè)即時(shí)通訊系統(tǒng)(附源碼)

開(kāi)發(fā) 后端
和各位讀者大致介紹下具體場(chǎng)景,線上的小程序中開(kāi)放一些語(yǔ)音麥克風(fēng)的房間,讓用戶進(jìn)入房間之后可以互相通過(guò)語(yǔ)音聊天的方式進(jìn)行互動(dòng)。

 項(xiàng)目背景

和各位讀者大致介紹下具體場(chǎng)景,線上的小程序中開(kāi)放一些語(yǔ)音麥克風(fēng)的房間,讓用戶進(jìn)入房間之后可以互相通過(guò)語(yǔ)音聊天的方式進(jìn)行互動(dòng)。

這里分享一下相關(guān)的技術(shù)設(shè)計(jì)方案。這款系統(tǒng)的核心點(diǎn)設(shè)計(jì)在于如何能讓一個(gè)用戶發(fā)出的語(yǔ)音通知到其他用戶上邊。語(yǔ)音數(shù)據(jù)在客戶端同事的處理下最終變成了io數(shù)據(jù)流請(qǐng)求到了后端,后端只需要將這些數(shù)據(jù)流傳達(dá)給各個(gè)不同的終端即可達(dá)到廣播通知的效果。

單機(jī)版架構(gòu)

最初期上線的時(shí)候,為了趕速度,快速試錯(cuò),所以簡(jiǎn)單地采用了單機(jī)版架構(gòu)去設(shè)計(jì)。結(jié)合技術(shù)棧為 SpringBoot,WebSocket,MySQL技術(shù)。

線上一間語(yǔ)音房間的同時(shí)在線人數(shù)并不會(huì)特別多,大概在15-50人的區(qū)間段內(nèi),系統(tǒng)核心代碼是通過(guò)SpringBoot內(nèi)部的WebSocket技術(shù)去進(jìn)行數(shù)據(jù)的主動(dòng)推送。

設(shè)計(jì)思路

整體的設(shè)計(jì)圖比較簡(jiǎn)單,基本就是一臺(tái)服務(wù)器存儲(chǔ)WebSocket連接,如下圖所示:

用戶進(jìn)行WebSocket初始化連接的時(shí)候需要一個(gè)連接分配和存儲(chǔ)的過(guò)程:

早期的存儲(chǔ)是存放在了服務(wù)器本地的一個(gè)Map集合中。

當(dāng)WebSocket進(jìn)行連接的時(shí)候就會(huì)往內(nèi)存中寫入一條數(shù)據(jù)信息,當(dāng)鏈接斷開(kāi)的時(shí)候,就將內(nèi)存中的數(shù)據(jù)移除。然后進(jìn)行語(yǔ)音廣播的時(shí)候需要結(jié)合WebSocket內(nèi)部的廣播發(fā)送功能進(jìn)行通知

看似設(shè)計(jì)比較簡(jiǎn)單,但是在后期業(yè)務(wù)變得龐大的時(shí)候出現(xiàn)了瓶頸。因?yàn)殡S著參加語(yǔ)音活動(dòng)用戶的增加,越來(lái)越多的WebSocketSession對(duì)象需要被存儲(chǔ)到內(nèi)存當(dāng)中,這種有狀態(tài)性的存儲(chǔ)對(duì)于單機(jī)擴(kuò)容不靈活。

設(shè)計(jì)缺陷

1.假設(shè)原先的服務(wù)器擴(kuò)容到了A,B兩臺(tái)機(jī)器,A用戶在A機(jī)器上邊建立了WebSocketSession,B用戶在B機(jī)器上邊建立的WebSocketSession連接。此時(shí)如果A想要和B進(jìn)行對(duì)話發(fā)送,需要先查找到具體WebSocketSession存放在哪臺(tái)機(jī)器上邊。

2.當(dāng)用戶出現(xiàn)了網(wǎng)絡(luò)異常,臨時(shí)斷開(kāi)連接進(jìn)行重連的時(shí)候,也可能會(huì)出現(xiàn)1所說(shuō)的問(wèn)題。

集群架構(gòu)

設(shè)計(jì)思路

一旦出現(xiàn)需要發(fā)送語(yǔ)音通知的時(shí)候,發(fā)送一條廣播的mq消息,每個(gè)機(jī)器都接收到消息之后,觸發(fā)自己的廣播操作即可。

RocketMq的接入系統(tǒng)設(shè)計(jì)里面mq采用的是廣播模式,這和我們通常使用的集群模式有一定的區(qū)別。

消息隊(duì)列RocketMQ版是基于發(fā)布或訂閱模型的消息系統(tǒng)。消費(fèi)者,即消息的訂閱方訂閱關(guān)注的Topic,以獲取并消費(fèi)消息。由于消費(fèi)者應(yīng)用一般是分布式系統(tǒng),以集群方式部署,因此消息隊(duì)列RocketMQ版約定以下概念:

  •  集群:使用相同Group ID的消費(fèi)者屬于同一個(gè)集群。同一個(gè)集群下的消費(fèi)者消費(fèi)邏輯必須完全一致(包括Tag的使用)。
  •  集群消費(fèi):當(dāng)使用集群消費(fèi)模式時(shí),消息隊(duì)列RocketMQ版認(rèn)為任意一條消息只需要被集群內(nèi)的任意一個(gè)消費(fèi)者處理即可。
  •  廣播消費(fèi):當(dāng)使用廣播消費(fèi)模式時(shí),消息隊(duì)列RocketMQ版會(huì)將每條消息推送給集群內(nèi)所有注冊(cè)過(guò)的消費(fèi)者,保證消息至少被每個(gè)消費(fèi)者消費(fèi)一次。

集群消費(fèi)模式適用場(chǎng)景 適用于消費(fèi)端集群化部署,每條消息只需要被處理一次的場(chǎng)景。此外,由于消費(fèi)進(jìn)度在服務(wù)端維護(hù),可靠性更高。具體消費(fèi)示例如下圖所示。

注意事項(xiàng)

  •  集群消費(fèi)模式下,每一條消息都只會(huì)被分發(fā)到一臺(tái)機(jī)器上處理。如果需要被集群下的每一臺(tái)機(jī)器都處理,請(qǐng)使用廣播模式。
  •  集群消費(fèi)模式下,不保證每一次失敗重投的消息路由到同一臺(tái)機(jī)器上。

廣播消費(fèi)模式適用場(chǎng)景 適用于消費(fèi)端集群化部署,每條消息需要被集群下的每個(gè)消費(fèi)者處理的場(chǎng)景。具體消費(fèi)示例如下圖所示。

注意事項(xiàng)

  •  廣播消費(fèi)模式下不支持順序消息。
  •  廣播消費(fèi)模式下不支持重置消費(fèi)位點(diǎn)。
  •  每條消息都需要被相同訂閱邏輯的多臺(tái)機(jī)器處理。
  •  消費(fèi)進(jìn)度在客戶端維護(hù),出現(xiàn)重復(fù)消費(fèi)的概率稍大于集群模式。
  •  廣播模式下,消息隊(duì)列RocketMQ版保證每條消息至少被每臺(tái)客戶端消費(fèi)一次,但是并不會(huì)重投消費(fèi)失敗的消息,因此業(yè)務(wù)方需要關(guān)注消費(fèi)失敗的情況。
  •  廣播模式下,客戶端每一次重啟都會(huì)從最新消息消費(fèi)。客戶端在被停止期間發(fā)送至服務(wù)端的消息將會(huì)被自動(dòng)跳過(guò),請(qǐng)謹(jǐn)慎選擇。
  •  廣播模式下,每條消息都會(huì)被大量的客戶端重復(fù)處理,因此推薦盡可能使用集群模式。
  •  廣播模式下服務(wù)端不維護(hù)消費(fèi)進(jìn)度,所以消息隊(duì)列RocketMQ版控制臺(tái)不支持消息堆積查詢、消息堆積報(bào)警和訂閱關(guān)系查詢功能。

這里面的應(yīng)用場(chǎng)景需要對(duì)集群內(nèi)部對(duì)每個(gè)消費(fèi)者都對(duì)服務(wù)器內(nèi)存中的socket連接進(jìn)行session是否存在對(duì)判斷,因此需要采用mq的廣播模式。

關(guān)于mq部分的接入代碼

Consumer模塊的配置: 

  1. package org.idea.web.socket.config;  
  2. import org.springframework.boot.context.properties.ConfigurationProperties;  
  3. /**  
  4.  * @Author linhao  
  5.  * @Date created in 10:30 上午 2021/5/10  
  6.  */  
  7. @ConfigurationProperties(prefix = "rocketmq.consumer" 
  8. public class MqConsumerConfig {  
  9.     private boolean isOn;  
  10.     private String groupName;  
  11.     private String nameSrvAddr;  
  12.     private String topics;  
  13.     private Integer consumeThreadMin;  
  14.     private Integer consumeThreadMax;  
  15.     private Integer consumeMessageBatchMaxSize;   
  16.      /**  
  17.      getter 和 setter部分省略  
  18.     **/  

Producer模塊的配置展示: 

  1. package org.idea.web.socket.config;  
  2. import org.springframework.boot.context.properties.ConfigurationProperties;  
  3. /**  
  4.  * @Author linhao  
  5.  * @Date created in 10:26 上午 2021/5/10  
  6.  */  
  7. @ConfigurationProperties(prefix = "rocketmq.producer" 
  8. public class MqProducerConfig {  
  9.     private boolean isOn;  
  10.     private String groupName;  
  11.     private String nameSrvAddr;  
  12.     private Integer maxMessageSize;  
  13.     private Integer sendMsgTimeout;  
  14.     private Integer retryTimesWhenSendFailed;   
  15.      /**  
  16.      getter 和 setter部分省略  
  17.     **/  

RocketMq內(nèi)部的消費(fèi)端Bean配置 

  1. package org.idea.web.socket.mq;  
  2. import lombok.extern.slf4j.Slf4j;  
  3. import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;  
  4. import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;  
  5. import org.apache.rocketmq.client.exception.MQClientException;  
  6. import org.apache.rocketmq.common.consumer.ConsumeFromWhere;  
  7. import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;  
  8. import org.idea.web.socket.config.MqConsumerConfig;  
  9. import org.idea.web.socket.config.MqProducerConfig;  
  10. import org.springframework.boot.autoconfigure.AutoConfigureAfter;  
  11. import org.springframework.boot.autoconfigure.AutoConfigureBefore;  
  12. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
  13. import org.springframework.boot.context.properties.EnableConfigurationProperties;  
  14. import org.springframework.context.annotation.Bean;  
  15. import org.springframework.context.annotation.Configuration;  
  16. import javax.annotation.Resource;  
  17. /**  
  18.  * @Author linhao  
  19.  * @Date created in 10:34 上午 2021/5/10  
  20.  */  
  21. @Configuration  
  22. @Slf4j  
  23. @EnableConfigurationProperties({MqConsumerConfig.class})  
  24. public class MqConsumerAutoConfig {  
  25.     @Resource  
  26.     private MqConsumerConfig mqConsumerConfig;  
  27.     @Resource  
  28.     //這個(gè)接口需要手動(dòng)實(shí)現(xiàn)順序消費(fèi)的邏輯 每次獲取到消息隊(duì)列的第一條數(shù)據(jù)  
  29.     private MessageListenerHandler messageListenerConcurrently;  
  30.     @Bean  
  31.     @ConditionalOnMissingBean  
  32.     public DefaultMQPushConsumer defaultMQPushConsumer() {  
  33.         DefaultMQPushConsumer consumer = new DefaultMQPushConsumer();  
  34.         consumer.setNamesrvAddr(mqConsumerConfig.getNameSrvAddr());  
  35.         consumer.setConsumerGroup(mqConsumerConfig.getGroupName());  
  36.         consumer.setConsumeThreadMin(mqConsumerConfig.getConsumeThreadMin());  
  37.         consumer.setConsumeThreadMax(mqConsumerConfig.getConsumeThreadMax());  
  38.         consumer.registerMessageListener(messageListenerConcurrently);  
  39.         consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);  
  40.         //消費(fèi)模型是什么?  
  41.         consumer.setMessageModel(MessageModel.BROADCASTING);  
  42.         //默認(rèn)一次拉取一條消費(fèi)  
  43.         consumer.setConsumeMessageBatchMaxSize(mqConsumerConfig.getConsumeMessageBatchMaxSize());  
  44.         //*表示訂閱所有的tag  
  45.         try {  
  46.             consumer.subscribe(mqConsumerConfig.getTopics(), "*");  
  47.             consumer.start();  
  48.             log.info("【 MqConsumerAutoConfig 】mq consumer is started!");  
  49.         } catch (Exception e) {  
  50.             log.error("mq start fail,e is ", e);  
  51.         }  
  52.         return consumer;  
  53.     }  

RocketMq的服務(wù)生產(chǎn)者Bean配置 

  1. package org.idea.web.socket.mq;  
  2. import lombok.extern.slf4j.Slf4j;  
  3. import org.apache.rocketmq.client.producer.DefaultMQProducer;  
  4. import org.idea.web.socket.config.MqProducerConfig;  
  5. import org.springframework.boot.autoconfigure.AutoConfigureAfter;  
  6. import org.springframework.boot.autoconfigure.AutoConfigureBefore;  
  7. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
  8. import org.springframework.boot.context.properties.EnableConfigurationProperties;  
  9. import org.springframework.context.annotation.Bean;  
  10. import org.springframework.context.annotation.Configuration;  
  11. import javax.annotation.Resource;  
  12. /**  
  13.  * @Author linhao  
  14.  * @Date created in 11:05 上午 2021/5/10  
  15.  */  
  16. @Configuration  
  17. @Slf4j  
  18. @EnableConfigurationProperties({MqProducerConfig.class})  
  19. public class MqProducerAutoConfig {  
  20.     @Resource  
  21.     private MqProducerConfig mqProducerConfig;  
  22.     @Bean  
  23.     @ConditionalOnMissingBean  
  24.     //意味著DefaultMQProducer的配置可以被覆蓋  
  25.     public DefaultMQProducer defaultMQProducer() {  
  26.         DefaultMQProducer producer = new DefaultMQProducer(mqProducerConfig.getGroupName());  
  27.         producer.setNamesrvAddr(mqProducerConfig.getNameSrvAddr());  
  28.         //沒(méi)有則自動(dòng)創(chuàng)建topic的key 
  29.  //        producer.setCreateTopicKey("AUTO_CREATE_TOPIC_KEY");  
  30.         producer.setMaxMessageSize(mqProducerConfig.getMaxMessageSize()); 
  31.         producer.setSendMsgTimeout(mqProducerConfig.getSendMsgTimeout());  
  32.         producer.setRetryTimesWhenSendFailed(mqProducerConfig.getRetryTimesWhenSendFailed());  
  33.         try {  
  34.             producer.start();  
  35.             log.info("【 MqProducerAutoConfig 】mq producer is started!");  
  36.         } catch (Exception e) {  
  37.             log.error("[MqProducerAutoConfig] start fail, e is ", e);  
  38.         }  
  39.         return producer;  
  40.     }  

然后是對(duì)RocketMq內(nèi)部發(fā)送消息事件的一層函數(shù)封裝 

  1. package org.idea.web.socket.mq;  
  2. import com.alibaba.fastjson.JSON;  
  3. import lombok.extern.slf4j.Slf4j;  
  4. import org.apache.commons.lang3.StringUtils;  
  5. import org.apache.rocketmq.client.producer.DefaultMQProducer;  
  6. import org.apache.rocketmq.client.producer.SendResult;  
  7. import org.apache.rocketmq.common.message.Message;  
  8. import org.apache.rocketmq.remoting.common.RemotingHelper;  
  9. import org.idea.web.socket.config.MqProducerConfig;  
  10. import org.idea.web.socket.dto.BroadcastMqDTO;  
  11. import org.springframework.stereotype.Component;  
  12. import javax.annotation.Resource;  
  13. import java.io.UnsupportedEncodingException;  
  14. /**  
  15.  * 消息廣播發(fā)送端  
  16.  *  
  17.  * @Author linhao  
  18.  * @Date created in 10:43 下午 2021/5/9  
  19.  */  
  20. @Component  
  21. @Slf4j  
  22. public class BroadcastMqProducer {  
  23.     @Resource  
  24.     private DefaultMQProducer defaultMQProducer;  
  25.     @Resource  
  26.     private MqProducerConfig mqProducerConfig;  
  27.     private static String TOPIC = "ws-topic" 
  28.     private static String TAGS = "ws-tag" 
  29.     public static Integer ALL_USER_RECEIVE_TYPE = 1 
  30.     public static Integer ONE_USER_RECEIVE_TYPE = 2 
  31.     /**  
  32.      * 點(diǎn)對(duì)點(diǎn)之間的消息發(fā)送  
  33.      *  
  34.      * @param destSessionKey  
  35.      * @param msg  
  36.      * @return  
  37.      */  
  38.     public SendResult sendWebSocketToUser(String destSessionKey,String msg) {  
  39.         if (StringUtils.isEmpty(msg)) {  
  40.             log.error("[sendWebSocketToUser] msg can not be null!");  
  41.             return null;  
  42.         }  
  43.         Message message = null 
  44.         SendResult sendResult = null 
  45.         try {  
  46.             BroadcastMqDTO broadcastMqDTO = new BroadcastMqDTO();  
  47.             broadcastMqDTO.setEventType(ONE_USER_RECEIVE_TYPE);  
  48.             broadcastMqDTO.setMessage(msg);  
  49.             broadcastMqDTO.setSessionKey(destSessionKey);  
  50.             message = new Message(TOPIC, TAGS, (JSON.toJSONString(broadcastMqDTO)).getBytes(RemotingHelper.DEFAULT_CHARSET));  
  51.             sendResult = defaultMQProducer.send(message);  
  52.         } catch (Exception e) { 
  53.              log.error("[sendWebSocketBroadcastMsg] e is ", e);  
  54.         }  
  55.         return sendResult;  
  56.     }  
  57.     /**  
  58.      * 廣播消息發(fā)送  
  59.      *  
  60.      * @param msg 
  61.      * @return  
  62.      */  
  63.     public SendResult sendWebSocketBroadcastMsg(String msg) {  
  64.         if (StringUtils.isEmpty(msg)) {  
  65.             log.error("[sendWebSocketBroadcastMsg] msg can not be null!");  
  66.             return null;  
  67.         }  
  68.         Message message = null 
  69.         SendResult sendResult = null 
  70.         try {  
  71.             BroadcastMqDTO broadcastMqDTO = new BroadcastMqDTO();  
  72.             broadcastMqDTO.setEventType(ALL_USER_RECEIVE_TYPE);  
  73.             broadcastMqDTO.setMessage(msg);  
  74.             message = new Message(TOPIC, TAGS, (JSON.toJSONString(broadcastMqDTO)).getBytes(RemotingHelper.DEFAULT_CHARSET));  
  75.             sendResult = defaultMQProducer.send(message);  
  76.         } catch (Exception e) {  
  77.             log.error("[sendWebSocketBroadcastMsg] e is ", e);  
  78.         }  
  79.         return sendResult;  
  80.     }  

對(duì)消息的訂閱模塊實(shí)現(xiàn)代碼如下: 

  1. package org.idea.web.socket.mq;  
  2. import com.alibaba.fastjson.JSON;  
  3. import com.oracle.tools.packager.Log;  
  4. import lombok.extern.slf4j.Slf4j;  
  5. import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;  
  6. import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;  
  7. import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;  
  8. import org.apache.rocketmq.common.message.MessageExt;  
  9. import org.idea.web.socket.dto.BroadcastMqDTO;  
  10. import org.idea.web.socket.manager.SocketManager;  
  11. import org.springframework.messaging.simp.SimpMessagingTemplate;  
  12. import org.springframework.stereotype.Component;  
  13. import org.springframework.util.CollectionUtils;  
  14. import org.springframework.web.socket.WebSocketSession;  
  15. import javax.annotation.Resource;  
  16. import java.util.List;  
  17. import static org.idea.web.socket.mq.BroadcastMqProducer.ALL_USER_RECEIVE_TYPE;  
  18. import static org.idea.web.socket.mq.BroadcastMqProducer.ONE_USER_RECEIVE_TYPE;  
  19. /**  
  20.  * @Author linhao  
  21.  * @Date created in 10:59 上午 2021/5/10  
  22.  */  
  23. @Component  
  24. @Slf4j  
  25. public class MessageListenerHandler implements MessageListenerConcurrently {  
  26.     @Resource  
  27.     private SocketManager socketManager;  
  28.     @Resource  
  29.     private SimpMessagingTemplate template;  
  30.     @Override  
  31.     public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {  
  32.         if (CollectionUtils.isEmpty(list)) {  
  33.             Log.info("receive empty msg");  
  34.             return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;  
  35.         }  
  36.         MessageExt messageExt = list.get(0);  
  37.         byte[] bytes = messageExt.getBody();  
  38.         String json = new String(bytes);  
  39.         BroadcastMqDTO broadcastMqDTO = JSON.parseObject(json, BroadcastMqDTO.class);  
  40.         log.info("[MessageListenerHandler] broadcastMqDTO is " + broadcastMqDTO);  
  41.         if (ALL_USER_RECEIVE_TYPE.equals(broadcastMqDTO.getEventType())) {  
  42.             log.info("[consumeMessage] 廣播發(fā)送消息:觸發(fā)----》消息內(nèi)容為:" + broadcastMqDTO);  
  43.             template.convertAndSend("/topic/sendTopic", broadcastMqDTO);  
  44.         } else if (ONE_USER_RECEIVE_TYPE.equals(broadcastMqDTO.getEventType())) {  
  45.             String sessionKey = broadcastMqDTO.getSessionKey();  
  46.             WebSocketSession webSocketSession = socketManager.get(sessionKey);  
  47.             if (webSocketSession != null) {  
  48.                 template.convertAndSendToUser(sessionKey, "/queue/sendUser", broadcastMqDTO.getMessage());  
  49.                 log.info("[consumeMessage] 點(diǎn)對(duì)點(diǎn)發(fā)送消息;觸發(fā)----》消息內(nèi)容為:" + broadcastMqDTO);  
  50.             }  
  51.         }  
  52.         return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;  
  53.     }  

整體設(shè)計(jì)結(jié)構(gòu)如下圖:

于是按照這個(gè)結(jié)構(gòu)進(jìn)行了一版本的緊急開(kāi)發(fā)迭代,原先的單臺(tái)服務(wù)器擴(kuò)展為了服務(wù)集群。

業(yè)務(wù)拓展后續(xù)產(chǎn)品經(jīng)理提出一個(gè)需求,要求支持在同一間房?jī)?nèi)的兩個(gè)用戶之間發(fā)送悄悄話功能。這就需要我們進(jìn)行一個(gè)點(diǎn)對(duì)點(diǎn)之間傳輸通訊的功能了。因此需要在mq通知到每臺(tái)機(jī)器的時(shí)候加一個(gè)本地Session遍歷的邏輯,如果當(dāng)前機(jī)器存有用戶token對(duì)應(yīng)的session變量,那么就單獨(dú)針對(duì)那個(gè)Session進(jìn)行WebSocket的發(fā)送通知。

設(shè)計(jì)弊端一旦某臺(tái)機(jī)器出現(xiàn)了異常崩潰,那么就意味著這臺(tái)機(jī)器上的所有語(yǔ)音連接可能會(huì)出現(xiàn)中斷情況。目前這一塊的問(wèn)題也在考慮解決,計(jì)劃是將WebSocketSession存入到分布式緩存的redis中保證數(shù)據(jù)可靠存儲(chǔ),但是在后續(xù)嘗試的時(shí)候發(fā)現(xiàn)WebSocketSession對(duì)象沒(méi)有實(shí)現(xiàn)序列化接口,在存儲(chǔ)到Redis的時(shí)候會(huì)出現(xiàn)異常。目前這個(gè)問(wèn)題還在尋找解決思路中,不知道各位讀者朋友們有什么好的思路。

遇到的問(wèn)題點(diǎn)用戶請(qǐng)求直接訪問(wèn)到了我們的內(nèi)部服務(wù)器,如果在請(qǐng)求的中間加入一臺(tái)nginx做負(fù)載均衡則需要在nginx中配置一些額外信息。

項(xiàng)目的源代碼比較多,這里我把核心部分的代碼整理了一份,感興趣的朋友可以到我的gitee上邊去下載:

https://gitee.com/IdeaHome_admin/socket-framework 

 

責(zé)任編輯:龐桂玉 來(lái)源: Java知音
相關(guān)推薦

2019-03-21 09:45:20

IM即時(shí)通訊CIM

2021-08-14 09:23:03

即時(shí)通訊IM互聯(lián)網(wǎng)

2011-10-20 22:25:49

網(wǎng)易即時(shí)通

2010-04-30 10:35:09

即時(shí)通訊MSN

2012-06-11 09:27:17

imo即時(shí)通訊

2011-06-30 10:50:24

即時(shí)通訊

2012-03-23 21:18:34

imo即時(shí)通訊

2020-09-30 18:00:48

JavaSpring BootIM

2011-08-04 14:50:07

263EM

2012-03-05 11:06:28

imo即時(shí)通訊

2013-10-16 11:32:55

imoRTX即時(shí)通訊

2012-03-30 10:47:05

imo

2021-10-20 05:55:22

即時(shí)通訊IM網(wǎng)絡(luò)

2024-01-24 09:51:47

Vue3.NET通訊功能

2012-03-29 13:47:18

即時(shí)通訊

2014-11-17 11:58:49

即時(shí)通訊云

2012-03-15 14:55:03

imo即時(shí)通訊

2012-05-07 10:20:55

imo即時(shí)通訊

2012-05-24 10:31:16

imo即時(shí)通訊
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美亚洲二区| 理论片中文字幕| 偷偷www综合久久久久久久| 3atv一区二区三区| 日韩中文字幕在线不卡| 亚州视频一区二区三区| 免费人成黄页网站在线一区二区 | 成人淫片在线看| 青娱乐国产精品| 日韩电影不卡一区| 欧美日韩高清影院| 欧美男女爱爱视频| 日本美女高清在线观看免费| 国产69精品久久99不卡| 国产不卡一区二区在线播放| 久久久久99精品成人片试看| 九九久久婷婷| 精品动漫一区二区三区在线观看| 别急慢慢来1978如如2| 新版中文在线官网| 欧美激情一区二区在线| 国产欧美日韩伦理| 一区二区视频免费| 一二三区精品| 欧美国产亚洲视频| 欧美精品日韩在线| 日韩深夜福利| 亚洲成人黄色在线观看| 狠狠干狠狠操视频| 欧美日韩视频免费观看| 精品久久久中文| mm131午夜| av网站在线免费播放| wwww国产精品欧美| 国产精品毛片一区视频| a级片在线视频| 日韩电影免费在线| 欧美一级bbbbb性bbbb喷潮片| 无码人妻精品一区二区三区夜夜嗨| 国产乱码精品一区二区亚洲 | 欧美二区不卡| 色多多国产成人永久免费网站 | 欧美中文在线观看| 国产一级aa大片毛片| 99热精品久久| 有码中文亚洲精品| 免费看污片的网站| 九九热爱视频精品视频| 亚洲免费伊人电影在线观看av| 丰满人妻一区二区三区大胸 | 国产九色精品| 亚洲第一天堂影院| 国产激情一区二区三区四区| 国产一区二区视频在线观看| 中文字幕第一页在线播放| 欧美一级网站| 国产成人激情小视频| 秋霞精品一区二区三区| 久久国产一二区| 热久久视久久精品18亚洲精品| 欧美日韩大片在线观看| 自拍偷拍欧美专区| 欧美精品制服第一页| 麻豆天美蜜桃91| 中文字幕av亚洲精品一部二部| 日韩视频免费大全中文字幕| 欧美一级特黄高清视频| 天天揉久久久久亚洲精品| 色噜噜狠狠色综合网图区| 久久久精品成人| 偷拍欧美精品| 欧美高清一级大片| 日韩精品一区二区在线播放| 香蕉久久a毛片| 国产国产精品人在线视| 一区二区三区黄| 国产麻豆精品在线| 国产尤物99| 国产裸舞福利在线视频合集| 国产精品美女www爽爽爽| 午夜啪啪免费视频| 牛牛在线精品视频| 亚洲成av人在线观看| 欧美日韩成人免费视频| 色猫猫成人app| 欧美一区二区三区日韩| 波多野结衣视频播放| 精品视频97| 欧美激情va永久在线播放| 在线观看 中文字幕| 秋霞成人午夜伦在线观看| 亚洲一区二区三区久久 | 97久久超碰国产精品| 日本一区二区三区视频在线播放| 麻豆网站在线| 天天av天天翘天天综合网色鬼国产| 国产精品涩涩涩视频网站| 亚洲tv在线| 亚洲丁香久久久| 国产精品18在线| 在线精品观看| 国产精品永久免费在线| 色婷婷av一区二区三区之e本道| 久久精品一区二区| 97碰在线视频| 精品福利在线| 亚洲精品自产拍| 人妻久久一区二区| 三级在线观看一区二区| 产国精品偷在线| a天堂中文在线88| 亚洲午夜成aⅴ人片| 欧美日韩一区二区三区69堂| 欧美一级全黄| 久久6精品影院| 亚洲天堂网在线观看视频| 99re6这里只有精品视频在线观看 99re8在线精品视频免费播放 | 影音成人av| 亚洲激情电影中文字幕| 日韩免费av一区| 久久性色av| 国产在线视频欧美一区二区三区| 嫩草香蕉在线91一二三区| 色就色 综合激情| 看全色黄大色黄女片18| 亚洲欧洲中文字幕| 国产精品美女呻吟| 日本电影一区二区在线观看| 亚洲午夜一区二区三区| 色黄视频免费看| 91亚洲成人| 国产精品普通话| 国产黄色片在线播放| 精品女同一区二区三区在线播放| 亚洲天堂网站在线| 大胆日韩av| 国产精品久久91| 免费看男男www网站入口在线| 午夜影院久久久| 韩国av中国字幕| 欧美二区不卡| 成人h在线播放| 永久免费网站在线| 日韩一级免费观看| 欧美性猛交xxxxx少妇| 日韩综合小视频| 欧美最大成人综合网| 亚洲国产欧美日本视频| 亚洲男人天堂视频| 免费黄色网址在线| 久久九九久久九九| 成人一区二区三| 不卡一区2区| 97超级碰在线看视频免费在线看| 国产农村老头老太视频| 国产丝袜欧美中文另类| 国产精品乱码久久久久| 日韩av大片| 国产欧美一区二区三区久久人妖| 欧洲不卡视频| 欧美一级片免费看| 国产真人真事毛片| youjizz久久| 中文字幕乱码人妻综合二区三区 | 亚洲男人第一av网站| 国产三级av片| 欧美激情一区三区| 国产探花在线观看视频| 激情综合中文娱乐网| 久久久一本精品99久久精品66| 婷婷激情一区| 日韩亚洲综合在线| 东京干手机福利视频| 懂色av中文一区二区三区天美| 88久久精品无码一区二区毛片| 日本欧美一区二区| 国产系列第一页| av成人综合| 日本欧美爱爱爱| 天天影视久久综合| 日韩欧美国产一区二区三区 | 18+激情视频在线| 亚洲国产日韩欧美在线动漫 | 欧美一级二级在线观看| 日本天堂网在线观看| 久久久精品免费免费| 三级一区二区三区| 99精品欧美| 中文字幕av导航| 久久香蕉精品香蕉| 国产精品视频免费在线| 婷婷在线播放| 国产亚洲成av人片在线观看桃| 国产日产亚洲系列最新| 欧美日韩一区二区精品| 欧美美女性生活视频| 北条麻妃一区二区三区| 色综合色综合色综合色综合| 亚洲欧洲日本一区二区三区| 伊人av成人| 欧美日韩看看2015永久免费| 91久久久久久久久久| 中文在线аv在线| 久久国产精品久久久久| 精品视频一二区| 精品国产成人系列| 91国产精品一区| 欧美性猛交xxxx乱大交| 欧美日韩一级大片| 中文字幕欧美三区| aaaa黄色片| 国产suv精品一区二区883| 一区二区三区 日韩| 中文久久精品| 成人免费看片视频在线观看| 精品视频免费| 欧美裸体网站| 欧美18免费视频| 2022国产精品| 日韩黄色碟片| 国产不卡av在线| 在线观看爽视频| 久久青草福利网站| 欧美女同一区| 久久久av网站| 91短视频版在线观看www免费| 国产视频在线观看一区二区| 欧美熟女一区二区| 日韩精品在线网站| 99在线小视频| 欧美日韩中文字幕精品| 麻豆精品久久久久久久99蜜桃| 亚洲大片精品永久免费| 久草视频手机在线观看| 亚洲嫩草精品久久| 国产美女高潮视频| 亚洲图片你懂的| 91麻豆精品成人一区二区| 中文字幕一区二区三区不卡在线| 久久久精品成人| 国产精品久久久久天堂| 91香蕉国产视频| 国产精品午夜免费| 1024在线看片| 国产精品欧美极品| 国产乱子轮xxx农村| 综合分类小说区另类春色亚洲小说欧美| wwwww黄色| 中文字幕中文字幕中文字幕亚洲无线| 91麻豆制片厂| 中文字幕在线观看不卡| 日本激情视频一区二区三区| 亚洲人亚洲人成电影网站色| 中文字幕求饶的少妇| 亚洲视频免费观看| 久久久久成人精品无码| 亚洲成人一二三| 二区视频在线观看| 日本韩国一区二区三区视频| 波多野结衣大片| 欧美日韩国产在线播放网站| 国产又粗又猛视频免费| 91麻豆精品国产91久久久使用方法 | 欧美羞羞免费网站| 亚洲午夜精品久久久| 欧美高清视频一二三区 | 91美女在线视频| 午夜精产品一区二区在线观看的| 国产欧美日韩不卡| 久久久精品少妇| 一区二区激情小说| 国产三级av片| 欧美精品日韩精品| 少妇高潮久久久| 国产亚洲xxx| 午夜羞羞小视频在线观看| **欧美日韩vr在线| 国产一区一一区高清不卡| 91免费看网站| 中国av一区| 国产四区在线观看| 99精品免费视频| 免费av不卡在线| 成人av免费网站| 大吊一区二区三区| 亚洲国产精品一区二区www| 久久永久免费视频| 日韩美女主播在线视频一区二区三区| 亚洲欧美日本在线观看| 最近免费中文字幕视频2019| 岛国毛片av在线| 国产精品香蕉国产| 国产成人一二| 一区二区视频国产| 国产日韩欧美三区| 99九九99九九九99九他书对| 99精品视频一区二区| 97在线观看免费高| 欧美日韩精品国产| av免费在线不卡| 国产午夜精品全部视频在线播放 | 日韩有码电影| 欧美成人精品xxx| 全亚洲第一av番号网站| 成人av男人的天堂| 午夜av一区| 蜜臀久久99精品久久久酒店新书| 国产成人免费在线观看不卡| 国产精品久久免费观看| 精品久久久久久中文字幕| 99热这里只有精品5| 揄拍成人国产精品视频| 这里有精品可以观看| 国产精品美女xx| 伊人色**天天综合婷婷| 亚洲不卡视频在线| 91污在线观看| 国产大片中文字幕| 欧美一级日韩免费不卡| 亚洲欧美视频一区二区| 国产成人精品视频在线观看| 国产精品午夜av| 国产精品久久久影院| 久久国产精品色| 免费看污片的网站| 一本色道亚洲精品aⅴ| 视频二区在线观看| 欧美高清视频在线观看| 欧美精品影院| 日韩一级片一区二区| 韩国午夜理伦三级不卡影院| 纪美影视在线观看电视版使用方法| 色综合久久久久| 三级视频网站在线| 91av视频在线免费观看| 大香伊人久久精品一区二区| 精品免费久久久久久久| 国产精品自在在线| 婷婷色中文字幕| 国产又粗又猛又黄视频| 亚洲欧美日韩中文在线| 男人最爱成人网| 欧美性大战久久久久| 久久久777| 日本少妇xxxxx| 欧美视频你懂的| 日本高清中文字幕在线| 成人激情视频在线播放| 自拍欧美日韩| 中文字幕在线国产| 天天亚洲美女在线视频| 色视频在线观看福利| 秋霞av国产精品一区| 国产亚洲一区| 加勒比av中文字幕| 一区二区三区精品在线观看| 手机av免费在线观看| 欧美一级高清免费播放| 国产区精品区| 九九九九九九九九| 一区二区三区在线不卡| 人妻少妇精品无码专区久久| 8x拔播拔播x8国产精品| 教室别恋欧美无删减版| 国产日韩欧美久久| 亚洲精品日产精品乱码不卡| 高清国产mv在线观看| 欧美中文字幕在线视频| 日韩片欧美片| 亚洲成人激情小说| 欧美日韩午夜视频在线观看| www日韩tube| 97神马电影| 久久精品毛片| 亚洲精品卡一卡二| 亚洲电影免费观看高清完整版在线观看| 蜜臀国产一区| 中国成人在线视频| 成人视屏免费看| 久久精品99北条麻妃| 久久99久久99精品中文字幕| 色先锋久久影院av| xxww在线观看| 亚洲不卡av一区二区三区| 久草福利在线视频| 亚洲a区在线视频| 国产精品日韩久久久| 秋霞欧美一区二区三区视频免费| 精品国产在天天线2019| 欧美色片在线观看| 国产激情片在线观看| 久久久久久久综合狠狠综合| 国产免费一区二区三区免费视频| 韩国精品久久久999| 成人在线丰满少妇av| 亚洲天堂av网站| 欧美久久久久久久久| 色戒汤唯在线观看| 中文字幕超清在线免费观看| 久久久一区二区三区|