针对golanggo语言http包和高并发下的websocket和golang高并发http请求这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展golanggorillawebsocket例
针对golang go语言 http包 和 高并发下的websocket和golang 高并发http请求这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展golang gorilla websocket例子、Golang websocket、golang websocket 入门、Golang websocket使用方法等相关知识,希望可以帮助到你。
本文目录一览:- golang go语言 http包 和 高并发下的websocket(golang 高并发http请求)
- golang gorilla websocket例子
- Golang websocket
- golang websocket 入门
- Golang websocket使用方法
golang go语言 http包 和 高并发下的websocket(golang 高并发http请求)
总结
以上是小编为你收集整理的golang go语言 http包 和 高并发下的websocket全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
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","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 { _,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/
Golang websocket
环境:Win10 + Go1.9.2
1. 先下载并引用 golang 的 websocket 库
①golang 的官方库都在 https://github.com/golang 下,而 websocket 库在 /net 下。
②如果没有安装 Git,需要先安装 Git。
③使用 go get -u github.com/golang/net/websocket 下载代码,将安装在环境变量 GOPATH 配置的路径中。
代码中使用路径为 "golang.org/x/net/websocket",在对应路径下没有代码的话则引用出错,可将对应代码放在 GOPAHT/golang.org/x/net 下。
2. 服务端 Go 代码
package main import ( "fmt" "golang.org/x/net/websocket" "net/http" "os" "time" ) //错误处理函数 func checkErr(err error, extra string) bool { if err != nil { formatStr := " Err : %s\n"; if extra != "" { formatStr = extra + formatStr; } fmt.Fprintf(os.Stderr, formatStr, err.Error()); return true; } return false; } func svrConnHandler(conn *websocket.Conn) { request := make([]byte, 128); defer conn.Close(); for { readLen, err := conn.Read(request) if checkErr(err, "Read") { break; } //socket被关闭了 if readLen == 0 { fmt.Println("Client connection close!"); break; } else { //输出接收到的信息 fmt.Println(string(request[:readLen])) time.Sleep(time.Second); //发送 conn.Write([]byte("World !")); } request = make([]byte, 128); } } func main() { http.Handle("/echo", websocket.Handler(svrConnHandler)); err := http.ListenAndServe(":6666", nil); checkErr(err, "ListenAndServe"); fmt.Println("Func finish."); }
PS:《Golang socket》中使用了 go coroutine 来处理 connection 的消息阻塞接收,websocket 不需要进行这样的处理,否则将报 use of closed network connection 的错误!
3.
①客户端 Go 代码
package main import ( "fmt" "golang.org/x/net/websocket" "os" "sync" ) var gLocker sync.Mutex; //全局锁 var gCondition *sync.Cond; //全局条件变量 var origin = "http://127.0.0.1:6666/" var url = "ws://127.0.0.1:6666/echo" //错误处理函数 func checkErr(err error, extra string) bool { if err != nil { formatStr := " Err : %s\n"; if extra != "" { formatStr = extra + formatStr; } fmt.Fprintf(os.Stderr, formatStr, err.Error()); return true; } return false; } //连接处理函数 func clientConnHandler(conn *websocket.Conn) { gLocker.Lock(); defer gLocker.Unlock(); defer conn.Close(); request := make([]byte, 128); for { readLen, err := conn.Read(request) if checkErr(err, "Read") { gCondition.Signal(); break; } //socket被关闭了 if readLen == 0 { fmt.Println("Server connection close!"); //条件变量同步通知 gCondition.Signal(); break; } else { //输出接收到的信息 fmt.Println(string(request[:readLen])) //发送 conn.Write([]byte("Hello !")); } request = make([]byte, 128); } } func main() { conn, err := websocket.Dial(url, "", origin); if checkErr(err, "Dial") { return; } gLocker.Lock(); gCondition = sync.NewCond(&gLocker); _, err = conn.Write([]byte("Hello !")); go clientConnHandler(conn); //主线程阻塞,等待Singal结束 for { //条件变量同步等待 gCondition.Wait(); break; } gLocker.Unlock(); fmt.Println("Client finish.") }
②如果客户端不使用 Go 代码,可以使用 Cocos Creator 的 js 代码
cc.Class({ extends: cc.Component, properties: { }, ctor: function () { this.ws = null; }, onLoad: function () { var self = this; this.ws = new WebSocket("ws://127.0.0.1:6666/echo"); this.ws.onopen = function (event) { console.log("Send Text WS was opened."); if (self.ws.readyState === WebSocket.OPEN) { self.ws.send("Hello !"); } else{ console.log("WebSocket instance wasn''t ready..."); } }; this.ws.onmessage = function (event) { console.log("response text msg: " + event.data); self.ws.send("Hello !"); }; this.ws.onerror = function (event) { console.log("Send Text fired an error"); }; this.ws.onclose = function (event) { console.log("WebSocket instance closed."); }; }, // called every frame update: function (dt) { }, });
golang websocket 入门
我们先写一个最简单的go http服务
package main import ( "net/http" ) func main() { http.HandleFunc("/",func(w http.ResponseWriter,r *http.Request) { w.Write([]byte("hello world")) }) http.ListenAndServe(":9000",nil) }
上面的太简单,就是一个http的服务,启动打开浏览器就可以输出hello world了,这是http,每次一个请求一个返回,虽然http的1.1版本已经支持keep-alive了,但如果想从服务发送到客户端,还是不行的,那么就诞生了websocket了。
现在改进一下代码:
package main import ( "net/http" "github.com/gorilla/websocket" "fmt" ) var upgrade = websocket.Upgrader{} func main() { http.HandleFunc("/",r *http.Request) { w.Write([]byte("hello world")) }) http.HandleFunc("/v1/ws",r *http.Request) { conn,_ := upgrade.Upgrade(w,r,nil) go func(conn *websocket.Conn) { for{ //mtype :TextMessage=1/BinaryMessage=-2/CloseMessage=8/PingMessage=9/PongMessage=10 mtype,msg,_:=conn.ReadMessage() switch mtype { case 1: conn.WriteMessage(mtype,msg) case 8: fmt.Println("close") } } }(conn) }) http.ListenAndServe(":9000",nil) }
这个里面如果请求的是v1/ws的话就进入websocket的,就是把用户的输入当做输出,返回到客户端。下面通过浏览器console测试一下
var ws = new WebSocket("ws://127.0.0.1:9000/v1/ws") ws.addEventListener("message",function(e){console.log(e);}); ws.send("123")
运行一下就可以看到效果。当然,如果你不想返回,只是在后端输出一下
mtype,_:=conn.ReadMessage() fmt.Println(mtype,":",string(msg))
那么前端就收不到任何返回。
进一步,那么如何后端推送呢,
http.HandleFunc("/v1/ws",func(w http.ResponseWriter,r *http.Request) { conn,_ := upgrade.Upgrade(w,nil) go func(conn *websocket.Conn) { ch :=time.Tick(5*time.Second) for range ch{ fmt.Println("call") conn.WriteMessage(1,[]byte("abc")) } }(conn) })
这样只要前端绑定了这个message就可以定时收到后端的推送了。但是如果前端关闭ws.close()将不会收到推送了。
在结束这篇blog之前还要补充一点就是服务关闭,如果前端关闭,后端任然继续读取数据将会报错panic: repeated read on Failed websocket connection。因为无法读取到客户端的数据了。所以还要在第一个例子的地方加上一个异常处理
mtype,err:=conn.ReadMessage() if err != nil{ conn.Close() return }
第一篇入门就和大家分享到这来
Golang websocket使用方法
package main import ( "fmt" "log" "net/http" "code.google.com/p/go.net/websocket" ) func main() { http.Handle("/",websocket.Handler(Echo)) if err := http.ListenAndServe(":1234",nil); err != nil { log.Fatal("ListenAndServer: ",err) } } func Echo(ws *websocket.Conn) { var err error for { var reply string if err = websocket.Message.Receive(ws,&reply); err != nil { fmt.Println("Can't receive") break } fmt.Println("Received back from client: ",reply) msg := "Received: " + reply fmt.Println("Sending to client" + msg) if err = websocket.Message.Send(ws,msg); err != nil { fmt.Println("Can't send") break } } }
关于golang go语言 http包 和 高并发下的websocket和golang 高并发http请求的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于golang gorilla websocket例子、Golang websocket、golang websocket 入门、Golang websocket使用方法的相关知识,请在本站寻找。
本文标签: