go語言程式設計之旅筆記4
阿新 • • 發佈:2020-10-31
第四章: websocket服務
-
簡介
我寫筆記的目的是為了記錄所用到的一些元件,但是從這章開始到結束元件不像前面多了。
ws可在單個tcp連線上建立全雙工通訊,允許服務端主動向客戶端輸出。保持連線狀態,是一種有狀態的應用層協議。建立方式通過可以http代理來握手,使用HTTP Upgrade頭進行協議升級。
-
庫選擇
書上寫了多種庫,包括nhooyr.io/websocket和gorilla/wesocket等,後者成熟功能多,前者更符合go的習慣並且有併發,完整關閉,可以編譯為wasm等好處。
go get -u nhooyr.io/websocket
-
基本用法
server.go
package main import ( "context" "fmt" "log" "net/http" "time" "nhooyr.io/websocket" "nhooyr.io/websocket/wsjson" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "HTTP Hello") }) http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) { conn, err := websocket.Accept(w, r, nil) if err != nil { log.Println(err) return } defer conn.Close(websocket.StatusInternalError, "internal error") ctx, cancel := context.WithTimeout(r.Context(), time.Second*10) defer cancel() var v interface{} err = wsjson.Read(ctx, conn, &v) if err != nil { log.Println(err) return } log.Printf("client resvered: %v\n", v) err = wsjson.Write(ctx, conn, "Hello websocket client.") if err != nil { log.Println(err) return } conn.Close(websocket.StatusNormalClosure, "") }) log.Fatal(http.ListenAndServe(":2021", nil)) }
client.go
package main import ( "context" "fmt" "time" "nhooyr.io/websocket" "nhooyr.io/websocket/wsjson" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() c, _, err := websocket.Dial(ctx, "ws://localhost:2021/ws", nil) if err != nil { panic(err) } defer c.Close(websocket.StatusInternalError, "internal error") err = wsjson.Write(ctx, c, "Hello websocket server") if err != nil { panic(err) } var v interface{} err = wsjson.Read(ctx, c, &v) if err != nil { panic(err) } fmt.Printf("resvered server's response : %v\n", v) c.Close(websocket.StatusNormalClosure, "") }
-
其他
github和部落格園都支援不了md的圖
sequenceDiagram client->>home/: HTTP / 請求首頁 home/->>client: 聊天室頁面 client->>webscoket: 通過ws協議請求: /ws webscoket->>webscoket: 協議轉換 webscoket->>client: 響應 webscoket->broadcast: channel通訊 webscoket->client: 通過ws長連線傳送訊息
程式碼沒有特別的,不仔細貼了,基本就是channel的操作,完整的還是去github。
一段單例的程式碼,雙檢鎖基本都長這樣,不過沒有看到‘易變’。golang有沒有這個東西我不記得了
package singleton import "sync" type singleton2 struct { count int } var ( instance2 *singleton2 mutex sync.Mutex ) func New() *singleton2 { if instance2 == nil { mutex.Lock() if instance2 == nil { instance2 = new(singleton2) } mutex.Unlock() } return instance2 } func (s *singleton2) Add() int { s.count++ return s.count }
在敏感詞處理環節介紹了DFA和貝葉斯分類演算法,提到了兩個庫
go get -u github.com/antlinker/go-dirtytilter go get -u github.com/jbrukh/bayesian
使用者識別用的token生成方式和之前章節一樣,離線訊息處理使用了內建的container/ring環形連結串列