golang gorilla websocket例子


WebSocket協議是基於TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。
WebSocket通信協議於2011年被IETF定為標准RFC 6455,並被RFC7936所補充規范。

在golang語言中,目前有兩種比較常用的實現方式:一個是golang自帶的庫,另一個是gorilla,功能強大。

golang自帶庫的使用例子可參考以前的博文:Golang如何使用websocket

本文以gorilla為例,介紹websocket的使用。

下載gorilla

# go get github.com/gorilla/websocket

下面例子中主要包括兩部分,server和client。
client部分又包括:web client(瀏覽器)和非web client。

server

server端是一個HTTP 服務器,監聽8080端口。

當接收到連接請求后,將連接使用的http協議升級為websocket協議。后續通信過程中,使用websocket進行通信。

對每個連接,server端等待讀取數據,讀到數據后,打印數據,然后,將數據又發送給client.

server啟動方式

# go run server.go

server.go代碼如下:

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build ignore package main import ( "flag" "html/template" "log" "net/http" "github.com/gorilla/websocket" ) var addr = flag.String("addr", "localhost:8080", "http service address") var upgrader = websocket.Upgrader{} // use default options func echo(w http.ResponseWriter, r *http.Request) { c, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("upgrade:", err) return } defer c.Close() for { mt, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) break } log.Printf("recv: %s", message) err = c.WriteMessage(mt, message) if err != nil { log.Println("write:", err) break } } } func home(w http.ResponseWriter, r *http.Request) { homeTemplate.Execute(w, "ws://"+r.Host+"/echo") } func main() { flag.Parse() log.SetFlags(0) http.HandleFunc("/echo", echo) http.HandleFunc("/", home) log.Fatal(http.ListenAndServe(*addr, nil)) } var homeTemplate = template.Must(template.New("").Parse(` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script> window.addEventListener("load", function(evt) { var output = document.getElementById("output"); var input = document.getElementById("input"); var ws; var print = function(message) { var d = document.createElement("div"); d.innerHTML = message; output.appendChild(d); }; document.getElementById("open").onclick = function(evt) { if (ws) { return false; } ws = new WebSocket("{{.}}"); ws.onopen = function(evt) { print("OPEN"); } ws.onclose = function(evt) { print("CLOSE"); ws = null; } ws.onmessage = function(evt) { print("RESPONSE: " + evt.data); } ws.onerror = function(evt) { print("ERROR: " + evt.data); } return false; }; document.getElementById("send").onclick = function(evt) { if (!ws) { return false; } print("SEND: " + input.value); ws.send(input.value); return false; }; document.getElementById("close").onclick = function(evt) { if (!ws) { return false; } ws.close(); return false; }; }); </script> </head> <body> <table> <tr><td valign="top" width="50%"> <p>Click "Open" to create a connection to the server, "Send" to send a message to the server and "Close" to close the connection. You can change the message and send multiple times. <p> <form> <button id="open">Open</button> <button id="close">Close</button> <p><input id="input" type="text" value="Hello world!"> <button id="send">Send</button> </form> </td><td valign="top" width="50%"> <div id="output"></div> </td></tr></table> </body> </html> `)) 

server output:

recv: 2018-10-20 17:09:12.497129965 +0800 CST m=+1.010137585
recv: 2018-10-20 17:09:13.495602484 +0800 CST m=+2.008641088
recv: 2018-10-20 17:09:14.49401062 +0800 CST m=+3.007080206
recv: 2018-10-20 17:09:15.497114615 +0800 CST m=+4.010215329
recv: 2018-10-20 17:09:16.494394706 +0800 CST m=+5.007526368
read: websocket: close 1000 (normal)

非web client

client啟動后,首先連接server。

連接建立后,主routine每一秒鍾向server發送消息(當前時間)。

另一個routine從server接收數據,並打印。

當client退出時,會向server發送關閉消息。接着,等待退出。

client啟動方式

# go run client.go

client代碼如下:

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build ignore package main import ( "flag" "log" "net/url" "os" "os/signal" "time" "github.com/gorilla/websocket" ) var addr = flag.String("addr", "localhost:8080", "http service address") func main() { flag.Parse() log.SetFlags(0) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"} log.Printf("connecting to %s", u.String()) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-done: return case t := <-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil { log.Println("write:", err) return } case <-interrupt: log.Println("interrupt") // Cleanly close the connection by sending a close message and then // waiting (with timeout) for the server to close the connection. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close:", err) return } select { case <-done: case <-time.After(time.Second): } return } } } 

client output:

connecting to ws://localhost:8080/echo
recv: 2018-10-20 17:09:12.497129965 +0800 CST m=+1.010137585
recv: 2018-10-20 17:09:13.495602484 +0800 CST m=+2.008641088
recv: 2018-10-20 17:09:14.49401062 +0800 CST m=+3.007080206
recv: 2018-10-20 17:09:15.497114615 +0800 CST m=+4.010215329
recv: 2018-10-20 17:09:16.494394706 +0800 CST m=+5.007526368
^Cinterrupt
read: websocket: close 1000 (normal)

web client

web client,也就是使用瀏覽器。
在瀏覽器中輸入http://127.0.0.1:8080

瀏覽器

"Open",然后"send"

server output:

recv: Hello world!!

參考

百度百科

https://baike.baidu.com/item/WebSocket

github

https://github.com/gorilla/websocket

doc

https://godoc.org/github.com/gorilla/websocket

example

https://github.com/gorilla/websocket/blob/master/examples/

Just try, don't shy.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM