>  기사  >  백엔드 개발  >  golang WebSocket 프로그래밍 팁: 동시 연결 처리

golang WebSocket 프로그래밍 팁: 동시 연결 처리

WBOY
WBOY원래의
2023-12-18 10:54:091058검색

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. Heartbeat 패킷

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

마지막으로 WebSocket 연결 끊김을 고려해야 합니다. WebSocket 서버를 구현할 때 클라이언트와 서버 간에 데이터가 전송될 때 적절한 삭제가 이루어지도록 연결 수명 주기를 고려해야 합니다.

다음은 WebSocket 연결을 끊기 위해 goroutine 및 select 문을 사용하는 방법을 보여주는 간단한 예입니다.

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

Summary

이 기사에서는 Golang WebSocket 프로그래밍에 대한 몇 가지 팁을 소개했습니다. 우리는 동시 연결을 처리하기 위해 고루틴과 채널을 사용하는 방법, 연결이 유효한지 확인하기 위해 하트비트 패킷을 보내는 방법, 연결이 끊어졌을 때 적절한 정리 작업을 수행하는 방법을 배웠습니다. 이 팁이 효율적인 WebSocket 서버를 작성하는 데 도움이 되기를 바랍니다.

위 내용은 golang WebSocket 프로그래밍 팁: 동시 연결 처리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:golang의 지도 소개다음 기사:golang의 지도 소개