websocket客戶端斷連問題(使用rabbitmq stomp中繼)

參考文章
http://jmesnil.net/stomp-websocket/doc/
https://www.toptal.com/java/stomp-spring-boot-websocket
http://www.mydlq.club/article/86/
https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/html/websocket.html

SpringBoot集成websocket, 并使用rabbitmq的stomp插件作為中繼服務(wù)

  • 如果不設(shè)置客戶端默認(rèn)使用guest,guest賬號登陸
// 設(shè)置客戶端登陸賬號
.setClientLogin(stompBrokerProperties.getUsername())
.setClientPasscode(stompBrokerProperties.getPassword())
指定客戶端使用的賬號.png
  • 配置中繼服務(wù)
@Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        if (log.isTraceEnabled()) {
            log.trace("host:{} port:{} username:{} password:{}", stompBrokerProperties.getHost(), stompBrokerProperties.getPort(), stompBrokerProperties.getUsername(), stompBrokerProperties.getPassword());
        }

        registry.setApplicationDestinationPrefixes("/my_app");
        // Enables a simple in-memory broker
        // registry.enableSimpleBroker("/topic", "/queue");
        // Use this for enabling a Full featured broker like RabbitMQ
        registry.enableStompBrokerRelay("/topic", "/queue")
            .setRelayHost(stompBrokerProperties.getHost())
            .setRelayPort(stompBrokerProperties.getPort())
            // Set client login account, client will send `ping` to relay interval
            .setClientLogin(stompBrokerProperties.getUsername())
            .setClientPasscode(stompBrokerProperties.getPassword())
            .setSystemLogin(stompBrokerProperties.getUsername())
            .setSystemPasscode(stompBrokerProperties.getPassword())
//          .setSystemHeartbeatSendInterval(100000)
//          .setSystemHeartbeatReceiveInterval(100000)
            .setUserRegistryBroadcast("/topic/simp-user-registry")
            .setUserDestinationBroadcast("/topic/unresolved-user-destination");
    }

問題:websocket客戶端大概在10幾分鐘左右會和中繼斷連

  • websocket客戶端和rabbitmq stomp中繼服務(wù)會定期發(fā)送和響應(yīng)ping,pong指令保活(紅色向下箭頭代表服務(wù)器響應(yīng)的消息,綠色向上箭頭代表客戶端發(fā)送的消息) ,經(jīng)觀察大概10幾分鐘,客戶端指令到達(dá)不了中繼服務(wù),然后中繼服務(wù)會主動關(guān)閉客戶端連接。
websocket客戶端?;?png

中繼主動關(guān)閉了客戶端連接.png
  • SockJS協(xié)議要求服務(wù)器發(fā)送心跳消息,以防止代理斷定連接掛起,Spring SockJS配置有一個名為heartbeatTime的屬性,你可以使用它來定制頻率。默認(rèn)情況下,在25秒后發(fā)送心跳,假設(shè)在該連接上沒有發(fā)送其他消息,這個25秒的值符合以下對公共互聯(lián)網(wǎng)應(yīng)用程序的IETF建議。SockJS添加了最少的消息框架,例如,服務(wù)器最初發(fā)送字母o(“open” frame),消息以["message1","message2"](json編碼數(shù)組)的形式發(fā)送,如果在25秒內(nèi)(默認(rèn)情況下)沒有消息流,則發(fā)送字母h("heartbeat" frame)和字母c("close" frame)來關(guān)閉會話。
    使用簡單內(nèi)存broker.png
# 后臺設(shè)置
// Enables a simple in-memory broker
registry.enableSimpleBroker("/topic", "/queue");

解決使用rabbit的stomp中繼導(dǎo)致的websocket客戶端斷連問題

經(jīng)觀察,客戶端斷連的時間不定,所以初步懷疑是由于公司網(wǎng)絡(luò)不穩(wěn)定,導(dǎo)致網(wǎng)絡(luò)抖動造成短時間之內(nèi)客戶端的ping到達(dá)不了rabbit的stomp中繼。stomp.js默認(rèn)的?;顣r間間隔是10s,經(jīng)觀察如果超過10s*2出現(xiàn)網(wǎng)絡(luò)故障,中繼就會認(rèn)為客戶端連接斷開,主動斷開客戶端連接。后把保活時間間隔設(shè)置成100s,觀察了一晚上,客戶端連接比較正常。


var stompClient = null;

function connect(username) {
    var socket = new SockJS('/my_ws');
    stompClient = Stomp.over(socket);
    stompClient.heartbeat.outgoing = 100000; // 100s,默認(rèn)10s
    stompClient.heartbeat.incoming = 100000; // 100s
    var headers = {
        'username': username
    };
    stompClient.connect(headers, function (frame) {
        console.log('Connected: ' + frame);

        // 點(diǎn)對點(diǎn)消息
        stompClient.subscribe('/user/queue/msg', function (msg) {
            console.log("queue:", msg.body);
        });

        // setTimeout(function () {
        //     // stompClient.send("/my_app/hello", {}, "hello");
        //     stompClient.send("/my_app/hello/clp", {}, "hello");
        // }, 2000);
    }, function (errorCallback) {
        console.log("斷開連接:", errorCallback);
    });
}
初始觀察時間.png
終了觀察時間.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容