温馨提示×

温馨提示×

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

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

websocket小案例

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

浏览器客户端:

<!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