Golang构建WebSocket服务器和客户端的示例详解
作者:吴佳浩
简介
本教程将教你如何使用Go语言构建WebSocket服务器和客户端,以实现双向 通信。我们将介绍如何创建一个WebSocket服务器,用于接收来自客户端的消息,以及如何创建一个WebSocket客户端,用于与服务器通信。我们还将介绍一个简单的HTML页面,演示如何在浏览器中使用WebSocket客户端与服务器进行通信。
操作
1.创建一个文件夹.
2.使用GO mod初始化go mod init your_module_name
3.创建文件
4.go get github.com/gorilla/websocket
WebSocket 服务器
首先,我们将创建一个WebSocket服务器,用于接收来自客户端的消息。我们使用github.com/gorilla/websocket
包来处理WebSocket连接。
WsServer.go
// 导入必要的包 import ( "fmt" "net" "net/http" "time" "github.com/gorilla/websocket" ) // 创建WsServer结构体 type WsServer struct { listener net.Listener addr string upgrade *websocket.Upgrader } // 初始化WsServer func NewWsServer() *WsServer { ws := new(WsServer) ws.addr = "0.0.0.0:10215" ws.upgrade = &websocket.Upgrader{ ReadBufferSize: 4096, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { if r.Method != "GET" { fmt.Println("method is not GET") return false } if r.URL.Path != "/ws" { fmt.Println("path error") return false } return true }, } return ws } // 处理WebSocket连接 func (self *WsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/ws" { httpCode := http.StatusInternalServerError reasePhrase := http.StatusText(httpCode) fmt.Println("path error ", reasePhrase) http.Error(w, reasePhrase, httpCode) return } conn, err := self.upgrade.Upgrade(w, r, nil) if err != nil { fmt.Println("websocket error:", err) return } fmt.Println("client connect:", conn.RemoteAddr()) go self.connHandle(conn) } // 处理WebSocket连接中的消息 func (self *WsServer) connHandle(conn *websocket.Conn) { defer func() { conn.Close() }() stopCh := make(chan int) go self.send(conn, stopCh) for { conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(5000))) _, msg, err := conn.ReadMessage() if err != nil { close(stopCh) if netErr, ok := err.(net.Error); ok { if netErr.Timeout() { fmt.Printf("ReadMessage timeout remote: %v\n", conn.RemoteAddr()) return } } if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) { fmt.Printf("ReadMessage other remote:%v error: %v \n", conn.RemoteAddr(), err) } return } fmt.Println("Received message:", string(msg)) } } // 向客户端发送消息 func (self *WsServer) send(conn *websocket.Conn, stopCh chan int) { self.send10(conn) for { select { case <-stopCh: fmt.Println("connection closed") return case <-time.After(time.Second * 1): data := fmt.Sprintf("Hello WebSocket test from server %v", time.Now().UnixNano()) err := conn.WriteMessage(1, []byte(data)) fmt.Println("Sending....") if err != nil { fmt.Println("send message failed ", err) return } } } } // 测试一次性发送10万条数据给客户端 func (self *WsServer) send10(conn *websocket.Conn) { for i := 0; i < 100000; i++ { data := fmt.Sprintf("Hello WebSocket test from server %v", time.Now().UnixNano()) err := conn.WriteMessage(1, []byte(data)) if err != nil { fmt.Println("send message failed ", err) return } } } // 启动WebSocket服务器 func (w *WsServer) Start() (err error) { w.listener, err = net.Listen("tcp", w.addr) if err != nil { fmt.Println("net listen error:", err) return } err = http.Serve(w.listener, w) if err != nil { fmt.Println("http serve error:", err) return } return nil } func main() { ws := NewWsServer() ws.Start() }
这是WebSocket服务器的代码。它创建一个WsServer
结构体,用于处理WebSocket连接。服务器会不断接收来自客户端的消息,并发送一些测试消息。你可以根据需要进行修改和扩展。
WebSocket 客户端
接下来,我们将创建一个WebSocket客户端,用于与服务器进行通信。我们将使用自定义的WebSocket客户端实现。
WsClient.go
package main import ( "fmt" "net" "net/http" "time" "github.com/gorilla/websocket" ) // 创建自定义WebSocket客户端 type VIL struct{} type DefaultWebSocket struct { _host string _isOpen bool _bufQueue []interface{} _bufCap int _call interface{} _socket *websocket.Conn } // 初始化自定义WebSocket客户端 func (self *VIL) DefaultWebSocket(host, call) { _host = host _isOpen = false _bufQueue = []interface{} _bufCap = 100 if call != nil { _call = call } else { _call = { onConnect: func(e) { fmt.Println("connect success ", e) }, onDisconnect: func(e) { fmt.Println("disconnect ", e) }, onMsg: func(data) { // fmt.Println("receive message ", data) }, } } _socket = new(websocket.Conn) _socket = websocket.DefaultDialer.Dial(_host, nil) _socket.binaryType = "arraybuffer" } // 设置发送消息缓存队列的容量 func (self *DefaultWebSocket) setBufferCap(cap) { if cap < 0 { fmt.Println("parameter value can not be less than 0") return } _bufCap = cap } // 发送消息 func (self *DefaultWebSocket) send(data) { if _isOpen && _socket != nil { _socket.send("") } else { if len(_bufQueue) < _bufCap { _bufQueue = append(_bufQueue, data) } } } // 关闭WebSocket连接 func (self *DefaultWebSocket) close() { _socket.Close(1000, "normal") _isOpen = false } // 处理WebSocket连接中的消息 func (self *DefaultWebSocket) handle() { go func() { for { _socket.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(5000))) _, message, err := _socket.ReadMessage() if err != nil { fmt.Println("Error while reading message:", err) return } _call.onMsg(message) } }() } // 向客户端发送消息 func (self *DefaultWebSocket) sendToServer() { go func() { for { select { case <-stopCh: fmt.Println("Interrupted, closing connection...") err := _socket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { fmt.Println("Error while sending close message:", err) return } select { case <-done: case <-time.After(time.Second): } return case <-time.After(time.Second * 1): data := fmt.Sprintf("Hello WebSocket test from client %v", time.Now().UnixNano()) err := _socket.WriteMessage(1, []byte(data)) if err != nil { fmt.Println("Error while sending message:", err) return } } } }() }
这是WebSocket客户端的代码。它创建了一个DefaultWebSocket
结构体,用于处理WebSocket连接。客户端会不断发送消息给服务器,并处理来自服务器的消息。你可以根据需要进行修改和扩展。
HTML 页面
最后,我们创建一个简单的HTML页面,用于在浏览器中使用WebSocket客户端与服务器进行通信。以下是HTML代码:
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket Example</title> </head> <body> </body> <script type="text/javascript" src="./index.js"></script> <script> let counter = 0; let isConnect = false; let handler = { onConnect: function (e) { isConnect = true; console.log("handler connect success ", e); var se = setInterval(function () { if (isConnect === false) { clearInterval(se); } console.log("setInterval", Date.now()); socket.send("Web browser setInterval"); }, 3000); }, onDisconnect: function (e) { isConnect = false; console.log("handler disconnect ", e); }, onMsg: function (data) { counter++; if (counter >= 2000) { counter = 0; console.log("handler receive message ", data); } } }; let socket = new VIL.DefaultWebSocket("ws://127.0.0.1:10215/ws", handler); </script> </html>
index.js
let VIL = (function () { let VIL = { }; function DefaultWebSocket(host, call) { let _host = host; let _isOpen = false; let _bufQueue = []; let _bufCap = 100; let _call = null; if("undefined" !== typeof call && call !== null){ _call = call }else{ _call = { onConnect:function (e) { console.log("connect success ", e); }, onDisconnect:function (e) { console.log("disconnect ", e); }, onMsg:function (data) { //console.log("receive message ", data) } } } let _socket = new WebSocket(_host); _socket.binaryType = "arraybuffer"; /** * 设置发送消息缓存队列的容量 * @param {number} cap * @constructor */ this.setBufferCap = function(cap){ if("number" !== typeof cap ){ console.error("parameter type is not number "); return ; } if(cap < 0){ console.error("parameter value can not less then 0"); return ; } _bufCap = cap; }; /** * 发送消息 * @param {string | ArrayBuffer } data * @constructor */ this.send = function(data){ if(_isOpen && _socket){ _socket.send(""); }else{ if (_bufQueue < _bufCap){ _bufQueue.push(data); } } }; this.close = function(){ _socket.close(1000, "normal"); }; _socket.onopen = function(even){ _isOpen = true; _call.onConnect(even); while (_bufQueue > 0){ _socket.send(_bufQueue.shift()); } }; _socket.onmessage = function(e){ let data = e.data; _call.onMsg(data); }; /** * 收到关闭连接 * @param even */ _socket.onclose = function(even){ _isOpen = false; _call.onDisconnect({host:_host, event:even}); }; /** * 收到错误 * @param err */ _socket.onerror = function(err){ _isOpen = false; _call.onDisconnect({host:_host, event:err}); }; } try{ VIL.EngineSocket = DefaultWebSocket ; }catch (e) { console.error("VILEngine error ", e); } return VIL; })();
这个HTML页面包括一个WebSocket客户端的JavaScript代码,它会连接到我们的服务器,并处理连接、断开连接和消息。在浏览器中打开这个页面后,你将能够与服务器进行WebSocket通信。
总结
在本教程中,我们创建了一个WebSocket服务器和客户端,并演示了如何在浏览器中使用WebSocket客户端与服务器进行通信。WebSocket提供了一种强大的方式来实现实时双向通信,适用于各种应用程序,如在线聊天、实时数据更新等。你可以根据需要进一步扩展这些示例,以构建更复杂的WebSocket应用程序。
以上就是Golang构建WebSocket服务器和客户端的示例详解的详细内容,更多关于go WebSocket的资料请关注脚本之家其它相关文章!