iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0

無論是在線聊天、多人遊戲、即時通知還是實時數據更新,都需要一個高效的方式來實現實時通信。Golang,提供了一個強大的工具來實現這種功能 - WebSocket。

實現即時通信

WebSocket 是一種在 瀏覽器伺服器 之間實現 全雙工 通信的協議,允許在 不重新載入 頁面的情況下,客戶端伺服器之間持續地傳遞數據。在 Golang 中,可以使用 gorilla/websocket 套件來實現 WebSocket 通信。

server 端
這個伺服器創建一個 WebSocket 伺服器,並在 /ws 路由上等待客戶端連接。當客戶端連接後,伺服器將持續地接收來自客戶端的消息,然後將它們返回給客戶端。

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func handleConnection(w http.ResponseWriter, r *http.Request) {
    // 升級HTTP連接為WebSocket連接
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer conn.Close()

    for {
        // 讀取客戶端發送的消息
        messageType, p, err := conn.ReadMessage()
        if err != nil {
            fmt.Println(err)
            return
        }

        // 將消息回傳給客戶端
        if err := conn.WriteMessage(messageType, p); err != nil {
            fmt.Println(err)
            return
        }
    }
}

func main() {
    http.HandleFunc("/ws", handleConnection)
    fmt.Println("WebSocket 伺服器運行在 :8080 端口")
    http.ListenAndServe(":8080", nil)
}

client 端
這個客戶端連接到我們剛剛創建的 WebSocket 伺服器,並持續地接收來自伺服器的消息。還處理了中斷信號,以確保在結束之前正確關閉連接。

package main

import (
    "fmt"
    "github.com/gorilla/websocket"
    "os"
    "os/signal"
    "time"
)

func main() {
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    u := fmt.Sprintf("ws://localhost:8080/ws")
    fmt.Println("正在連接到", u)

    c, _, err := websocket.DefaultDialer.Dial(u, nil)
    if err != nil {
        fmt.Println("連接失敗:", err)
        return
    }
    defer c.Close()

    done := make(chan struct{})

    go func() {
        defer close(done)
        for {
            _, message, err := c.ReadMessage()
            if err != nil {
                fmt.Println("接收消息失敗:", err)
                return
            }
            fmt.Printf("接收到消息: %s\n", message)
        }
    }()

    for {
        select {
        case <-done:
            return
        case <-interrupt:
            fmt.Println("接收到中斷信號,關閉連接...")
            err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            if err != nil {
                fmt.Println("關閉連接失敗:", err)
                return
            }
            select {
            case <-done:
            case <-time.After(time.Second):
            }
            return
        }
    }
}

碎語

長輩都說,中秋過後每下一次雨,溫度都會下降一些,不知道這次颱風來下降的溫度還會不會回升?


上一篇
18 | 簡單說 Protocol Buffers
下一篇
20 | 救命,我不想寫SQL
系列文
Go 語言學習手札30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言