首頁  >  文章  >  後端開發  >  Go WebSocket 伺服器如何搭建?

Go WebSocket 伺服器如何搭建?

WBOY
WBOY原創
2024-05-31 22:47:59810瀏覽

如何搭建 Go WebSocket 伺服器:安裝 gorilla/websocket 函式庫。建立一個 HTTP 伺服器,處理 WebSocket 握手請求。升級 HTTP 請求到 WebSocket 連線。在伺服器端處理 WebSocket 訊息,包括傳送和接收資料。可擴展伺服器以允許客戶端訂閱特定頻道並僅接收來自這些頻道的訊息。

Go WebSocket 服务器如何搭建?

建立 Go WebSocket 伺服器

WebSocket 是全雙工通訊協議,允許客戶端和伺服器在單一 TCP 連接上進行雙向資料傳輸。 Go 語言為建立 WebSocket 伺服器提供了強大的支援。本文將介紹如何使用 Go 建立一個 WebSocket 伺服器,並附帶實戰案例。

入門

首先,你需要一個 Go 開發環境,其中包含 Go 編譯器和一個程式碼編輯器。你還需要安裝 gorilla/websocket 函式庫,它提供了 Go 語言的 WebSocket 實作。

go get -u github.com/gorilla/websocket

建立伺服器

WebSocket 伺服器本質上是一個傳統的 HTTP 伺服器,但它處理的是 WebSocket 握手請求。以下是如何在 Go 中建立 WebSocket 伺服器:

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/websocket"
)

func main() {
    // 升级 HTTP 请求到 WebSocket 连接
    upgrader := websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
    }

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Fatal(err)
        }

        // websocket.Conn 是一个双向的连接
        for {
            // 从客户端接收消息
            messageType, p, err := conn.ReadMessage()
            if err != nil {
                log.Fatal(err)
            }

            // 将消息返回客户端
            if err := conn.WriteMessage(messageType, p); err != nil {
                log.Fatal(err)
            }
        }
    })

    http.ListenAndServe(":8080", nil)
}

實戰案例

現在,我們來擴展這個伺服器,允許客戶端訂閱特定的頻道並僅接收來自這些頻道的訊息。

package main

import (
    "fmt"
    "log"
    "net/http"
    "sync"

    "github.com/gorilla/websocket"
)

type channel struct {
    sync.Mutex
    clients map[*websocket.Conn]bool
}

var channels = struct {
    sync.RWMutex
    m map[string]*channel
}{m: make(map[string]*channel)}

func NewChannel(name string) *channel {
    channels.Lock()
    defer channels.Unlock()

    if _, ok := channels.m[name]; !ok {
        channels.m[name] = &channel{clients: make(map[*websocket.Conn]bool)}
    }
    return channels.m[name]
}

func main() {
    upgrader := websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
    }

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Fatal(err)
        }

        // 订阅和取消订阅频道
        go func() {
            for {
                // 从客户端接收消息
                messageType, p, err := conn.ReadMessage()
                if err != nil {
                    log.Fatal(err)
                }

                // 如果消息是一种订阅请求,则将连接添加到相应频道
                if messageType == websocket.TextMessage && string(p)[:4] == "join" {
                    channelName := string(p)[5:]
                    channel := NewChannel(channelName)

                    // 锁定频道的客户端列表
                    channel.Lock()
                    channel.clients[conn] = true
                    // 解锁频道的客户端列表
                    channel.Unlock()
                }

                // 如果消息是一种取消订阅请求,则将连接从相应频道中移除
                if messageType == websocket.TextMessage && string(p)[:7] == "leave" {
                    channelName := string(p)[8:]
                    channel := NewChannel(channelName)

                    channel.Lock()
                    delete(channel.clients, conn)
                    channel.Unlock()
                }
            }
        }()

        // 广播消息到客户端
        go func() {
            for {
                // 分别广播来自每个频道的消息
                channels.RLock()
                for _, channel := range channels.m {
                    channel.RLock()
                    for client := range channel.clients {
                        if err := client.WriteMessage(websocket.TextMessage, "hello"); err != nil {
                            // 如果写入失败,则从频道中移除连接
                            channel.Lock()
                            delete(channel.clients, client)
                            channel.Unlock()
                        }
                    }
                    channel.RUnlock()
                }
                channels.RUnlock()
            }
        }()
    })

    http.ListenAndServe(":8080", nil)
}

現在,你可以啟動伺服器並使用 WebSocket 用戶端連接到 /ws 端點,訂閱頻道,並接收來自該頻道的訊息。

以上是Go WebSocket 伺服器如何搭建?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn