Go websocket


目的

使用go语言实现websocket服务端

逻辑

本示例主要使用gorilla/websocket框架将http请求升级成websocket协议

项目结构

.
├── go.mod
├── go.sum
├── index.html
├── main.go
└── socket.json

客户端

index.html

<!DOCTYPE html>
<html>
 
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>TestWebsocket</title>
 
    <script type="text/javascript">
        function LinkServer() {
            // 声明连接
            var Server_Com;
            if ("WebSocket" in window) {
                Server_Com = new WebSocket("ws://localhost:13000/getTime");
                console.log("新建连接到->localhost:13000");
            }
 
            // 建立连接后发送
            Server_Com.onopen = function() {
 
                Server_Com.send("Hello Server!"); // Web Socket 已连接上,使用 send() 方法发送数据
                console.log("已连接上服务器");
            }
 
            // 接收服务器消息
            Server_Com.onmessage = function(event) {
                var recv_msg = event.data;
 
                if (recv_msg == "Hello Client!") {
                    console.log("接收到服务器的问候: " + recv_msg); // 用于提示收到信息
                } else {
                    document.getElementById("Time").textContent = recv_msg; // 实时更新显示服务器发回的时间
                    console.log("接收到服务器数据: " + recv_msg);
                }
            }
        }
    </script>
</head>
 
<body>
    <p>服务器时间:</p>
    <p id="Time">2022-05-29 20:00:00</p>
 
    <button onclick="LinkServer()">连接</button>
 
</body>
 
</html>

服务端

解决跨越问题

var upgrader = websocket.Upgrader{
	// 解决跨域问题
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

main函数

func main() {
	// 注册服务器事件
	http.HandleFunc("/", Index)
	http.HandleFunc("/getTime", SendTime) // 支持多端同时访问,相当于收到不同请求后未每个请求分别创建线程处理
	fmt.Println("已向 DefaultServeMux 注册 SendTime 事件")

	// 打开要侦听的前端请求连接端口
	err := http.ListenAndServe(":13000", nil) // 这里是接受对本机所有的通过13000的请求,本机有多个IP则可在端口号前加IP地址区分,如"10.11.100.123:13000"
	if err != nil {
		fmt.Println("端口侦听错误:", err)
	}
}

这里监听了2个路由:

  • “/“:用于浏览器访问首页,通过Index读取index.html文件并且返回
  • “getTime”:index.html页面中js通过websocket连接到这个路由,通过SendTime函数处理请求并返回结果

main函数开启了tcp协议的13000端口,通过http服务向外暴露

Index

这个函数主要就是读取index.html文件并返回给前端

func Index(w http.ResponseWriter, r *http.Request) {
	index, err := ioutil.ReadFile("index.html")
	if err != nil {
		fmt.Println(err)
		return
	}
	n, err := w.Write(index)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("n:", n)
}

SendTime

这个函数主要是将http连接转换成websocket连接,处理完成后循环返回数据

func SendTime(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Print("升级websocket连接错误:", err)
		return
	}

	defer c.Close()

	// 接受消息
	mt, message, err := c.ReadMessage()
	if err != nil {
		fmt.Println("接收错误:", err)
	} else {

		fmt.Println("接收到前端消息:", string(message))

		// 发送问候
		var sendbuff string = "Hello Client!"
		c.WriteMessage(mt, []byte(sendbuff)) // 为阅读方便,省去错误处理

		// 不停地循环发送时间
		fmt.Println("开始发送时间")
		for {
			sendbuff = time.Now().Format("2006-01-02 15:04:05")
			err = c.WriteMessage(mt, []byte(sendbuff))
			if err != nil {
				fmt.Println("发送错误:", err)
				break
			}

			fmt.Println("发送时间:", sendbuff)
			time.Sleep(1 * time.Second) // 间隔1s,降低资源消耗,如果想提高实时性可减少时间间隔
		}

		fmt.Println("停止发送时间")
	}
}

运行

1.使用pm2后台运行服务:pm2 start socket.json

2.浏览器访问:localhost:13000

upload successful

服务器端日志:

upload successful

点击连接之后,页面上就可以实时展示服务器上的时间了

源代码:https://github.com/ZBIGBEAR/websocket

参考

[1]websocket

[2]golang服务端与web前端使用websocket通信

[3]Go-一个使用websocket的例子


文章作者: Alex
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alex !
  目录