WebSocket :記錄WebSocket onError錯誤用法導致的BUG

目錄:

項目背景

本篇記錄WebSocket :用WebSocket實現推送你必須考慮的幾個問題 onError錯誤用法導致的一個bug(同一種client類型只能登陸一個設備,具體代碼可以參見 : http://download.csdn.net/download/shangmingtao/9920532) ,代碼:

    /*
    Close
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId,
                        Session session) {
        log.info("[WebSocketServer] Close Connection : userId = " + userId);
        WebSocketUtils.remove(userId);
    }

    /*
    Error
     */
    @OnError
    public void onError(@PathParam("userId") String userId,
                        Throwable throwable,
                        Session session) {
        log.info("[WebSocketServer] Connection Exception : userId = "+ userId + " , throwable = " + throwable.getMessage());
        WebSocketUtils.remove(userId);//清除userId和session對應關係
    }

WebSocket連接流程圖:

這裏寫圖片描述

bug復現條件 :

client端連接上WebSocket後斷開網絡 ->打開網絡 ->重新連接.

bug現象:

服務端拋出TCP reset異常, reset異常觸發onError回調方法, 上述代碼中onError中會清除userId和session的對應關係.但實際清除的並不是舊鏈接的session和userId的對應關係.因爲我們用map或者redis存儲userId和session對應關係時是一個K-V存儲,新的會覆蓋舊的.

bug原因:

斷開網絡前:
這裏寫圖片描述

斷開網絡後:
這裏寫圖片描述

造成RST包的原因 :

  • 端口未打開
  • 請求超時
  • 提前關閉 (當本端斷開連接(不論什麼原因TCP四次揮手未到達對端),另一端發送消息到本端會觸發本端回覆RST包),這也是本bug原因.至於[PSH,ACK]具體是那條消息的ACK我沒有深究.

解決思路&方案:

很多網上WebSocket服務端代碼對於生產環境應用來講都誤導了大家,onClose方法和onError方法處理一模一樣.但實際這兩個方法分別是不同情況的回調.一個是關閉一個是異常.雖然很多時候觸發onError方法後會觸發onClose.比如網絡異常導致連接異常,然後ws關閉了連接.但是也有一些情況是僅觸發onError方法.比如上邊的server端close掉連接,然後接到RST包這種情況.
所以我們的處理方案是在onError回調中僅打印一條日誌或者針對不同的異常寫邏輯.無論怎麼處理都不可以在onError方法中接觸userId和session之間的對應關係.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章