// 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 ignorepackagemainimport ("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 optionsfuncecho(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 } }}funchome(w http.ResponseWriter, r *http.Request) { homeTemplate.Execute(w, "ws://"+r.Host+"/echo")}funcmain() { 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>`))
// 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 ignorepackagemainimport ("flag""log""net/url""os""os/signal""time""github.com/gorilla/websocket")var addr = flag.String("addr", "localhost:8080", "http service address")funcmain() { flag.Parse() log.SetFlags(0) interrupt :=make(chanos.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(chanstruct{})gofunc() {deferclose(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:returncase 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 } }}
浏览器端和客户端连接的是同一个HandlerFunc,即/echo路径所注入的echo(w http.ResponseWriter, r *http.Request)方法,在方法体中通过websocket.Upgrader对象的Upgrade()方法将连接升级为websocket协议的连接,通过调用websocket连接的ReadMessage()方法,从客户端读取一个消息。当没有消息过来时,会处于阻塞状态;当连接断开时,则会引发错误。将响应的结果通过websocket连接的WriteMessage()方法进行返回。