Heim >Backend-Entwicklung >Golang >golang WebSocket-Programmiertipps: Umgang mit gleichzeitigen Verbindungen

golang WebSocket-Programmiertipps: Umgang mit gleichzeitigen Verbindungen

WBOY
WBOYOriginal
2023-12-18 10:54:091132Durchsuche

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

Golang ist eine leistungsstarke Programmiersprache, und ihre Verwendung in der WebSocket-Programmierung wird von Entwicklern zunehmend geschätzt. WebSocket ist ein TCP-basiertes Protokoll, das eine bidirektionale Kommunikation zwischen Client und Server ermöglicht. In diesem Artikel stellen wir vor, wie Sie mit Golang einen effizienten WebSocket-Server schreiben, der mehrere gleichzeitige Verbindungen gleichzeitig verarbeitet. Bevor wir die Techniken vorstellen, lernen wir zunächst, was WebSocket ist.

Einführung in WebSocket

WebSocket ist ein Vollduplex-Kommunikationsprotokoll, das den Aufbau einer dauerhaften Verbindung zwischen dem Client und dem Server ermöglicht und so eine bidirektionale Kommunikation in Echtzeit ermöglicht. Im Gegensatz zu HTTP sind WebSocket-Verbindungen bidirektional und der Server kann aktiv Nachrichten an den Client senden, ohne auf eine Anfrage des Clients warten zu müssen.

Sobald der Client bei einer WebSocket-Verbindung eine Verbindungsanforderung initiiert, kann der Server die hergestellte TCP-Verbindung verwenden, um Daten an den Client zu senden. Der Client und der Server können Nachrichten ereignisartig überwachen und verarbeiten. Wenn ein Ereignis ausgelöst wird, können sowohl der Client als auch der Server die von der anderen Partei gesendeten Daten empfangen.

Golang WebSocket-Programmiertipps

Lassen Sie uns nun untersuchen, wie Sie mit Golang einen effizienten WebSocket-Server schreiben, der mehrere gleichzeitige Verbindungen gleichzeitig verarbeitet. Hier sind einige Tipps zur Golang WebSocket-Programmierung:

  1. Gleichzeitige Verbindungen

Beim Schreiben eines WebSocket-Servers müssen wir gleichzeitige Verbindungen berücksichtigen. Wir müssen sicherstellen, dass der Server mehrere Clients verarbeiten kann, die gleichzeitig Verbindungen herstellen, und gleichzeitig die Unabhängigkeit jeder Verbindung wahren. Um dieses Ziel zu erreichen, können wir Goroutinen und Kanäle in der Go-Sprache verwenden.

Hier ist ein einfaches Beispiel, das zeigt, wie mit mehreren gleichzeitigen Verbindungen mithilfe von Goroutinen und Kanälen umgegangen wird:

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. Heartbeat-Paket

Da es sich bei der WebSocket-Verbindung um eine dauerhafte Verbindung handelt, kann sie aus verschiedenen Gründen unterbrochen werden, z. B. aufgrund eines Netzwerkfehlers oder Browser-Neustart. Um dies zu verhindern, sollten wir von Zeit zu Zeit ein Heartbeat-Paket an den Client senden, um sicherzustellen, dass die Verbindung aktiv bleibt.

Hier ist ein einfaches Beispiel, das zeigt, wie Goroutine und Timer zum Implementieren von Heartbeat-Paketen verwendet werden:

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. Disconnection

Abschließend müssen wir die Trennung von WebSocket-Verbindungen berücksichtigen. Bei der Implementierung eines WebSocket-Servers müssen wir den Lebenszyklus der Verbindung berücksichtigen, damit bei der Datenübertragung zwischen Client und Server eine ordnungsgemäße Bereinigung erfolgt.

Hier ist ein einfaches Beispiel, das zeigt, wie man Goroutine und Select-Anweisungen verwendet, um die Trennung von WebSocket-Verbindungen zu erreichen:

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)
        }
    }
}

Zusammenfassung

In diesem Artikel haben wir einige Tipps zur Golang WebSocket-Programmierung vorgestellt. Wir haben gelernt, wie man Goroutinen und Kanäle verwendet, um gleichzeitige Verbindungen zu verarbeiten, wie man Heartbeat-Pakete sendet, um sicherzustellen, dass die Verbindung gültig bleibt, und wie man entsprechende Bereinigungsvorgänge durchführt, wenn die Verbindung getrennt wird. Wir hoffen, dass diese Tipps Ihnen beim Schreiben effizienter WebSocket-Server hilfreich sind.

Das obige ist der detaillierte Inhalt vongolang WebSocket-Programmiertipps: Umgang mit gleichzeitigen Verbindungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn