gin websocket 簡單分散式實現

wanhf11發表於2018-03-18

main.go

import (
    "github.com/gin-gonic/gin"
)

func main() {
    ...
    // 連線ws會先發Get,正常返回101
    r.GET("/ws", func(c *gin.Context) {
        WsHandler(c.Writer, c.Request)
    })
    ...
    r.Run()
}

handler.go

websocket接入:

import "github.com/gorilla/websocket"

var wsupgrader = websocket.Upgrader{
    ReadBufferSize:   1024,
    WriteBufferSize:  1024,
    HandshakeTimeout: 5 * time.Second,
    // 取消ws跨域校驗
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

// 處理ws請求
func WsHandler(w http.ResponseWriter, r *http.Request) {
    var conn *websocket.Conn
    var err error
    conn, err = wsupgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("Failed to set websocket upgrade: %+v", err)
        return
    }

    // 必須死迴圈,gin通過協程呼叫該handler函式,一旦退出函式,ws會被主動銷燬
    for {
        // recieve
        t, reply, err := conn.ReadMessage()
        if err != nil {
            break
        }

        // todo:業務操作
    }
}

分散式擴充套件,使用rds或者kafka等解耦合
當ws建立連線後,可輪詢共享記憶體(rds)是否有新訊息,若有新訊息,則往ws寫資料。
配合客戶端重連機制,很好實現分散式長連線IM和PUSH擴充套件。

// 業務操作呼叫寫rds
func SendMsg2Rds(uid int64, msg *WsMsg) {
    // list 或者 pubsub 結構
}
// 業務操作呼叫讀rds
func ReadMsgFromRds(uid int64) *WsMsg {
    // list 或者 pubsub 結構
}

// 協程輪詢rds:go RevAndSend
func RevAndSend(uid int64,ws *websocket.Conn) {
    for {
        // 若ws斷開,則break
        if msg := ReadMsgFromRds(uid); msg != nil {
            // 向rds寫資料 
            ws.WriteMessage(websocket.TextMessage, []byte(msg.ToJson()))
        }
    }
}

websocket 握手協議

客戶端會傳送Get請求,帶有核心欄位:

Upgrade: websocket
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

服務端會將101作為返回碼返回,作為握手成功的標示

相關文章