ホームページ >バックエンド開発 >Golang >golang WebSocket プログラミングのヒント: 同時接続の処理

golang WebSocket プログラミングのヒント: 同時接続の処理

WBOY
WBOYオリジナル
2023-12-18 10:54:091133ブラウズ

golang WebSocket编程技巧:处理并发连接

Golang は強力なプログラミング言語であり、WebSocket プログラミングでの Golang の使用は開発者の間でますます評価されています。 WebSocket は、クライアントとサーバー間の双方向通信を可能にする TCP ベースのプロトコルです。この記事では、Golang を使用して、複数の同時接続を同時に処理する効率的な WebSocket サーバーを作成する方法を紹介します。テクニックを紹介する前に、まず WebSocket とは何かを学びましょう。

WebSocket の概要

WebSocket は、クライアントとサーバー間で永続的な接続を確立できるようにする全二重通信プロトコルで、これによりリアルタイムの双方向通信が可能になります。 HTTP とは異なり、WebSocket 接続は双方向であり、サーバーはクライアントの要求を待たずに、クライアントにプロアクティブにメッセージを送信できます。

WebSocket 接続では、クライアントが接続要求を開始すると、サーバーは確立された TCP 接続を使用してクライアントにデータを送信できます。クライアントとサーバーは、イベントのような方法でメッセージを監視および処理でき、イベントがトリガーされると、クライアントとサーバーの両方が相手から送信されたデータを受信できます。

Golang WebSocket プログラミングのヒント

次に、Golang を使用して、複数の同時接続を同時に処理する効率的な WebSocket サーバーを作成する方法を学習しましょう。 Golang WebSocket プログラミングに関するヒントをいくつか紹介します。

  1. 同時接続

WebSocket サーバーを作成するときは、同時接続を考慮する必要があります。サーバーが、各接続の独立性を維持しながら、同時に接続を確立する複数のクライアントを処理できることを確認する必要があります。この目標を達成するには、Go 言語のゴルーチンとチャネルを使用します。

これは、ゴルーチンとチャネルを使用して複数の同時接続を処理する方法を示す簡単な例です:

package main

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

var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan []byte)           // broadcast channel

// Configure the upgrader
var upgrader = websocket.Upgrader{}

func main() {
    // Create a simple file server
    fs := http.FileServer(http.Dir("public"))
    http.Handle("/", fs)

    // Configure websocket route
    http.HandleFunc("/ws", handleConnections)

    // Start listening for incoming chat messages
    go handleMessages()

    // Start the server on localhost:8000
    log.Println("http server started on :8000")
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
    // Upgrade initial GET request to a websocket
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Make sure we close the connection when the function returns
    defer ws.Close()

    // Register our new client
    clients[ws] = true

    for {
        // Read in a new message
        _, msg, err := ws.ReadMessage()
        if err != nil {
            log.Printf("error: %v", err)
            delete(clients, ws)
            break
        }

        // Send the newly received message to the broadcast channel
        broadcast <- msg
    }
}

func handleMessages() {
    for {
        // Grab the next message from the broadcast channel
        msg := <-broadcast

        // Send it out to every client that is currently connected
        for client := range clients {
            err := client.WriteMessage(websocket.TextMessage, msg)
            if err != nil {
                log.Printf("error: %v", err)
                client.Close()
                delete(clients, client)
            }
        }
    }
}
  1. ハートビート パケット

WebSocket 接続によるこれは永続的な接続であり、ネットワーク障害やブラウザの再起動など、さまざまな理由で中断される可能性があります。これを防ぐには、時々ハートビート パケットをクライアントに送信して、接続がアクティブなままであることを確認する必要があります。

次は、ゴルーチンとタイマーを使用してハートビート パケットを実装する方法を示す簡単な例です。

package main

import (
    "github.com/gorilla/websocket"
    "time"
)

// Configure the upgrader
var upgrader = websocket.Upgrader{}

func handleConnection(ws *websocket.Conn) {
    // Set the read deadline for the connection
    ws.SetReadDeadline(time.Now().Add(5 * time.Second))

    for {
        // Read a message from the client
        _, _, err := ws.ReadMessage()
        if err != nil {
            if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) ||
                websocket.IsCloseError(err, websocket.CloseGoingAway) {
                // The client has closed the connection
                return
            } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
                // A timeout has occurred, send a ping message to the client
                ping(ws)
            } else {
                // Some other error has occurred
                log.Println(err)
                return
            }
        }
    }
}

// Send a PING message to the client
func ping(ws *websocket.Conn) {
    if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
        log.Println(err)
        ws.Close()
    }
}

// Start the server on localhost:8000
func main() {
    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        ws, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Println(err)
            return
        }

        // Handle the connection using a goroutine
        go handleConnection(ws)
    })

    http.ListenAndServe(":8000", nil)
}
  1. Disconnect

最後に、 WebSocket 接続を考慮する必要があります。 WebSocket サーバーを実装するときは、クライアントとサーバーの間でデータが転送されるときに適切なサニタイズが行われるように、接続のライフサイクルを考慮する必要があります。

以下は、Goroutine と select ステートメントを使用して WebSocket 接続の切断を実現する方法を示す簡単な例です。

package main

import (
    "github.com/gorilla/websocket"
)

var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Message)
var unregister = make(chan *websocket.Conn)

func main() {
    http.HandleFunc("/ws", handleConnections)

    go handleMessages()

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

type Message struct {
    Type int    `json:"type"`
    Body string `json:"body"`
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
    upgrader := websocket.Upgrader{}
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println(err)
        return
    }
    defer ws.Close()

    clients[ws] = true

    for {
        var msg Message
        err := ws.ReadJSON(&msg)
        if err != nil {
            if websocket.IsCloseError(err, websocket.CloseGoingAway) {
                unregister <- ws
                break
            }
            log.Printf("error: %v", err)
            continue
        }
        broadcast <- msg
    }
}

func handleMessages() {
    for {
        select {
        case msg := <-broadcast:
            for client := range clients {
                err := client.WriteJSON(msg)
                if err != nil {
                    log.Printf("error: %v", err)
                    unregister <- client
                    break
                }
            }
        case client := <-unregister:
            delete(clients, client)
        }
    }
}

概要

この記事では、いくつかのことを紹介しました。 Golang WebSocket プログラミングに関するヒント。ゴルーチンとチャネルを使用して同時接続を処理する方法、ハートビート パケットを送信して接続が有効なままであることを確認する方法、接続が切断されたときに適切なクリーンアップ操作を実行する方法を学びました。これらのヒントが効率的な WebSocket サーバーの作成に役立つことを願っています。

以上がgolang WebSocket プログラミングのヒント: 同時接続の処理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。