Golang は強力なプログラミング言語であり、WebSocket プログラミングでの Golang の使用は開発者の間でますます評価されています。 WebSocket は、クライアントとサーバー間の双方向通信を可能にする TCP ベースのプロトコルです。この記事では、Golang を使用して、複数の同時接続を同時に処理する効率的な WebSocket サーバーを作成する方法を紹介します。テクニックを紹介する前に、まず WebSocket とは何かを学びましょう。
WebSocket の概要
WebSocket は、クライアントとサーバー間で永続的な接続を確立できるようにする全二重通信プロトコルで、これによりリアルタイムの双方向通信が可能になります。 HTTP とは異なり、WebSocket 接続は双方向であり、サーバーはクライアントの要求を待たずに、クライアントにプロアクティブにメッセージを送信できます。
WebSocket 接続では、クライアントが接続要求を開始すると、サーバーは確立された TCP 接続を使用してクライアントにデータを送信できます。クライアントとサーバーは、イベントのような方法でメッセージを監視および処理でき、イベントがトリガーされると、クライアントとサーバーの両方が相手から送信されたデータを受信できます。
Golang WebSocket プログラミングのヒント
次に、Golang を使用して、複数の同時接続を同時に処理する効率的な WebSocket サーバーを作成する方法を学習しましょう。 Golang WebSocket プログラミングに関するヒントをいくつか紹介します。
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) } } } }
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) }
最後に、 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 サイトの他の関連記事を参照してください。