WebSocket 介紹

websocket 提供一種在client與server間全雙工通訊的方式。其通訊協定可參考:RFC 6455

websocket 通訊方式

記憶體使用量

如果照正常程式設計,要服務百萬個連線,大約要20GB左右的記憶體。因此必須要對程式做最佳化,以免記憶體使用過大。

  • goroutines
  • select / poll:定期踢掉不在線上或斷線的使用者連線。(syscall.Timeval, syscall.Select)
  • epoll

Go 語言使用函數

基本上Go提供:”golang.org/x/net/websocket” 供使用者使用。不過大多使用者會使用:”github.com/gorilla/websocket” 提供比較完整的使用方式。

server.go 範例
package main

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

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Home page")
}

func reader(conn *websocket.Conn) {
	for {
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		log.Println(string(p))
		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true }

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}
	log.Println("Client Successfully connected...")
	reader(ws)
}

func setRoutes() {
	http.HandleFunc("/", homePage)
	http.HandleFunc("/ws", wsEndpoint)
}

func main() {
	setRoutes()
	log.Fatal(http.ListenAndServe(":8080", nil))
}
index.html
<!DOCTYPE html>
<html lang="zh_TW">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Ws Example</title>
   </head>
   <body>
      <script>
         let socket = new WebSocket("ws://localhost:8080/ws");
         
         socket.onopen = function() {
            socket.send("Hi from the client.");
         };

         socket.onmessage = function(msg) {
            console.log(msg);
         };

         socket.onclose = function(event) {
         };

         socket.onerror = function(error) {
            console.log("error", error);
         }
      </script>
   </body>
</html>

參考資料