Maison >développement back-end >Golang >Conseils de programmation Golang WebSocket : gestion des connexions simultanées

Conseils de programmation Golang WebSocket : gestion des connexions simultanées

WBOY
WBOYoriginal
2023-12-18 10:54:091133parcourir

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

Golang est un langage de programmation puissant et son utilisation dans la programmation WebSocket est de plus en plus appréciée par les développeurs. WebSocket est un protocole basé sur TCP qui permet une communication bidirectionnelle entre le client et le serveur. Dans cet article, nous expliquerons comment utiliser Golang pour écrire un serveur WebSocket efficace qui gère plusieurs connexions simultanées en même temps. Avant de présenter les techniques, apprenons d'abord ce qu'est WebSocket.

Introduction à WebSocket

WebSocket est un protocole de communication full-duplex qui permet d'établir une connexion persistante entre le client et le serveur, permettant une communication bidirectionnelle en temps réel. Contrairement à HTTP, les connexions WebSocket sont bidirectionnelles et le serveur peut envoyer activement des messages au client sans avoir à attendre que le client en fasse la demande.

Dans une connexion WebSocket, une fois que le client lance une demande de connexion, le serveur peut utiliser la connexion TCP établie pour envoyer des données au client. Le client et le serveur peuvent surveiller et traiter les messages de manière événementielle. Lorsqu'un événement est déclenché, le client et le serveur peuvent recevoir les données envoyées par l'autre partie.

Conseils de programmation Golang WebSocket

Etudions maintenant comment utiliser Golang pour écrire un serveur WebSocket efficace qui gère plusieurs connexions simultanées en même temps. Voici quelques conseils sur la programmation Golang WebSocket :

  1. Connexions simultanées

Lors de l'écriture d'un serveur WebSocket, nous devons prendre en compte les connexions simultanées. Nous devons nous assurer que le serveur peut gérer plusieurs clients établissant des connexions simultanément tout en conservant l'indépendance de chaque connexion. Pour atteindre cet objectif, nous pouvons utiliser des goroutines et des canaux en langage Go.

Voici un exemple simple qui montre comment gérer plusieurs connexions simultanées à l'aide de goroutines et de canaux :

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

Étant donné que la connexion WebSocket est une connexion persistante, elle peut être interrompue pour diverses raisons, telles qu'une panne de réseau. ou redémarrage du navigateur. Afin d'éviter que cela ne se produise, nous devons envoyer un paquet de battements de cœur au client de temps en temps pour garantir que la connexion reste active.

Voici un exemple simple qui montre comment utiliser goroutine et timer pour implémenter des paquets de battements de cœur :

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. Déconnexion

Enfin, nous devons considérer la déconnexion des connexions WebSocket. Lors de la mise en œuvre d'un serveur WebSocket, nous devons prendre en compte le cycle de vie de la connexion afin qu'une désinfection appropriée se produise lorsque les données sont transférées entre le client et le serveur.

Voici un exemple simple qui montre comment utiliser les instructions goroutine et select pour réaliser la déconnexion des connexions 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)
        }
    }
}

Résumé

Dans cet article, nous avons présenté quelques conseils sur la programmation Golang WebSocket. Nous avons appris comment utiliser des goroutines et des canaux pour gérer les connexions simultanées, comment envoyer des paquets de battement de cœur pour garantir que la connexion reste valide et comment effectuer les opérations de nettoyage appropriées lorsque la connexion est déconnectée. Nous espérons que ces conseils vous seront utiles pour écrire des serveurs WebSocket efficaces.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn