温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

websocket小案例

发布时间:2020-07-18 09:09:45 来源:网络 阅读:719 作者:梁十八 栏目:编程语言

浏览器客户端:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>websocket测试程序 </title> <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 (ev) { if (ws) { return false; } ws = new WebSocket("ws://127.0.0.1:8888/ws"); ws.onopen = function (ev) { print("连接成功"); }; ws.onclose = function (ev) { print("连接关闭"); }; ws.onerror = function (ev) { print("发生错误 " + ev.data) }; ws.onmessage = function (ev1) { print("服务端消息: " + ev1.data) }; return false }; document.getElementById("send").onclick = function (ev) { if (!ws) { return false } if (input.value !== "") { ws.send(input.value) } else { print("发送内容不能为空") } }; document.getElementById("close").onclick = function (ev) { if (ws) { ws.close() } } }) </script> </head> <body> <div> <br> websocket测试程序,消息又客户端发送到server然后原封不动的返回,server使用go实现 <br> <br> <br> <input type="button" value="连接" id="open"> <input placeholder="输入要发送的消息..." id="input"> <input type="button" value="发送" id="send"> <input type="button" value="关闭" id="close"> </div> <div id="output"> </div> </body> </html>

版本一:

websocket小案例

package main import ( "net/http" "github.com/gorilla/websocket" ) var ( // http升级websocket协议的配置 upgrader = websocket.Upgrader{ // 允许所有CORS跨域请求 CheckOrigin: func(r *http.Request) bool { return true }, } ) func wsHandler(writer http.ResponseWriter, request *http.Request) { var ( conn *websocket.Conn err error //msgType int data []byte ) //完成握手应答 if conn, err = upgrader.Upgrade(writer, request, nil); err != nil { return } //数据收发 for { //数据类型有text、binary,此处选text if _, data, err = conn.ReadMessage(); err != nil { goto ERR } if err = conn.WriteMessage(websocket.TextMessage, data); err != nil { goto ERR } } ERR: conn.Close() } func main() { http.HandleFunc("/ws", wsHandler) http.ListenAndServe("127.0.0.1:8888", nil) }

版本一未做优化

版本二:

websocket小案例

connection.go:

package impl import ( "github.com/gorilla/websocket" "sync" "errors" ) type Connection struct { wsConn *websocket.Conn // 底层websocket inChan chan []byte // 读队列 outChan chan []byte // 写队列 closeChan chan byte // 关闭通知 isClosed bool mutex sync.Mutex // 避免重复关闭管道 } //封装websocket长连接 func InitConnection(wsConn *websocket.Conn) (conn *Connection, err error) { conn = &Connection{ wsConn: wsConn, inChan: make(chan []byte, 1000), outChan: make(chan []byte, 1000), closeChan: make(chan byte, 1), } //启动读协程 go conn.readLoop() //启动写协程 go conn.writeLoop() return } func (conn *Connection) ReadMessage() (data []byte, err error) { select { case data = <- conn.inChan: case <- conn.closeChan: err = errors.New("connection is closed") } return } func (conn *Connection) WriteMessage(data []byte) (err error) { select { case conn.outChan <- data: case <- conn.closeChan: err = errors.New("connection is closed") } return } func (conn *Connection) Close() { // wsConn.Close是线程安全的,可重入的(可以多次关闭) conn.wsConn.Close() //一个chan只能关闭一次(所以要保证这行代码只执行一次) conn.mutex.Lock() if !conn.isClosed{ close(conn.closeChan) conn.isClosed = true } conn.mutex.Unlock() } //内部实现 func (conn *Connection) readLoop() { var ( data []byte err error ) //不停的读 for { if _, data, err = conn.wsConn.ReadMessage(); err != nil { goto ERR } //阻塞在这里,等待inChan有空闲位置 select { case conn.inChan <- data: case <- conn.closeChan: //当closeChan被关闭就进入这个分支 goto ERR } } ERR: conn.Close() } func (conn *Connection) writeLoop() { var ( data []byte err error ) //不停写 for { select { case data = <-conn.outChan: case <- conn.closeChan: goto ERR } if err = conn.wsConn.WriteMessage(websocket.TextMessage, data); err != nil{ goto ERR } } ERR: conn.Close() }

server.go:

package main import ( "net/http" "github.com/gorilla/websocket" "./impl" "time" ) var ( // http升级websocket协议的配置 upgrader = websocket.Upgrader{ // 允许所有CORS跨域请求 CheckOrigin: func(r *http.Request) bool { return true }, } ) func wsHandler(writer http.ResponseWriter, request *http.Request) { var ( wsConn *websocket.Conn err error //msgType int data []byte conn *impl.Connection ) //完成握手应答 if wsConn, err = upgrader.Upgrade(writer, request, nil); err != nil { return } if conn, err = impl.InitConnection(wsConn); err != nil { goto ERR } // 不停发送心跳信息 go func() { var ( err error ) for { if err = conn.WriteMessage([]byte("heartbeat")); err != nil { return } time.Sleep(time.Second) } }() for { if data, err = conn.ReadMessage(); err != nil { goto ERR } if err = conn.WriteMessage(data); err != nil { goto ERR } } ERR: // 关闭连接的操作 conn.Close() /*//数据收发 for { //数据类型有text、binary,此处选text if _, data, err = conn.ReadMessage(); err != nil { goto ERR } if err = conn.WriteMessage(websocket.TextMessage, data); err != nil { goto ERR } } ERR: conn.Close()*/ } func main() { http.HandleFunc("/ws", wsHandler) http.ListenAndServe("127.0.0.1:8888", nil) }

做了封装,线程安全

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI