GO提供原生的websocket API,使用時go get然後引用即可
golang.org/x/net/websocket
使用起來也很方便,直接上代碼吧。 一個echo server的代碼
package mainimport( "golang.org/x/net/websocket" "fmt" "net/http" "flag")type WSServer struct { ListenAddr string}func (this *WSServer)handler(conn *websocket.Conn){ fmt.Printf("a new ws conn: %s->%s\n", conn.RemoteAddr().String(), conn.LocalAddr().String()) var err error for { var reply string err = websocket.Message.Receive(conn, &reply) if err != nil { fmt.Println("receive err:",err.Error()) break } fmt.Println("Received from client: " + reply) if err = websocket.Message.Send(conn, reply); err != nil { fmt.Println("send err:", err.Error()) break } }}func (this *WSServer)start()(error){ http.Handle("/ws", websocket.Handler(this.handler)) fmt.Println("begin to listen") err := http.ListenAndServe(this.ListenAddr, nil) if err != nil { fmt.Println("ListenAndServe:", err) return err } fmt.Println("start end") return nil}func main(){ addr := flag.String("a", "127.0.1.1:12345", "websocket server listen address") flag.Parse() wsServer := &WSServer{ ListenAddr : *addr, } wsServer.start() fmt.Println("------end-------")}
上述代碼中,每來一個新的websocket client,server會起一個goroutine執行WSSever的handler函數。 websocket client代碼執行個體
package mainimport ( "flag" "fmt" "time" "golang.org/x/net/websocket")var addr = flag.String("addr", "127.0.0.1:12345", "http service address")func main() { flag.Parse() url := "ws://"+ *addr + "/ws" origin := "test://1111111/" ws, err := websocket.Dial(url, "", origin) if err != nil { fmt.Println(err) } go timeWriter(ws) for { var msg [512]byte _, err := ws.Read(msg[:])//此處阻塞,等待有資料可讀 if err != nil { fmt.Println("read:", err) return } fmt.Printf("received: %s\n", msg) }}func timeWriter(conn *websocket.Conn) { for { time.Sleep(time.Second * 2) websocket.Message.Send(conn, "hello world") }}
client的代碼,每隔2秒鐘發送hello world到server,然後阻塞在Read函數。需要注意的是origin必須以“http://1111111/” 這種標準的URI格式,否則報錯“invalid URI for request”。 關閉進程、網路斷線等異常情況 關閉進程
無論server還是client,關閉進程,對端Read都會立刻收到EOF,對EOF做處理即可。 網路斷線 測試
client和server部署在不同機器上,client每隔2秒中向server發送資料,server收到後回吐給用戶端。這個過程中,拔掉client的網線。 測試結果
斷網後,client一定時間內寫都能成功返回,但是因為斷網實際沒有發送出去,資料寫到了底層tcp的緩衝區。 過一段時間後,1分鐘左右,client Read返回錯誤“read: operation timed out”。Write會返回“write: broken pipe”。這個可能是Go中websocket實現時加了逾時機制,也有可能是設定了底層TCP SO_KEEPALIVE,檢測到了網路不可用。 在Read/Write返回錯誤之前,重新連上網路,可以繼續發送和接受資料。這個可以從TCP的實現上解釋。TCP串連並不是物理串連,本質上就是串連兩端各自系統核心維護的一個四元組。用戶端斷線,在一定時間內並不會導致四元組的釋放。所以當連上網線後此TCP串連可以自動回復,繼續進行正常的網路操作。 斷線重連到其他網路,相當於斷網。這個很好解釋,連上其他網路,IP地址都改變了,之前的四元組不可用。