Gin集成WebSocket

Gin集成WebSocket

概述

这篇笔记记录在Gin框架下使用WebSocket通讯协议与Web前端(Vue2)通讯的简易实现。
WebSocket是一种网络通讯协议,它允许在客户端和服务器之间进行全双工通信。与传统的HTTP请求不同,WebSocket提供了一种双向通信机制,服务器可以主动向客户端推送信息,而客户端也可以随时发送信息给服务器;由于WebSocket建立在一个长连接上,它比频繁建立新连接的HTTP轮询更高效和节能,因此WebSocket的实时性非常适合做需要实时数据交换的应用,如在线游戏,聊天应用等。
此外WebSocket是HTML5规范的一部分,得到现代浏览器的广泛支持,并提供了一套API(包括WebSocket构造函数用于创建链接、以及用于发送和接收数据的方法)

思路

在开始动手实现之前,我们需要先知道 websocket客户端和服务端都是怎么连接上的,以及它们是怎么保持连接的?

websocket的连接步骤

  1. 1. 握手阶段。客户端会先发起Websocket连接时,发送一个HTTP请求到服务器到服务器。服务器收到请求后会进行一系列验证,包括检查协议版本、Origin、Sec-WebSocket-Key等。如果验证通过则返回HTTP 101状态码,表示成功切换到WebSocket协议。

  2. 2. 保持连接。WebSocket连接建立后,客户端和服务器之间会保持打开状态,实现随时发送消息的功能,不需要频繁创建和关闭连接。

  3. 3. 心跳机制。为了保持连接的活跃性,Websocket使用心跳机制。客户端和服务器会定期发送一个特定的消息以确保连接处于活动状态,如果一方长时间没有收到心跳消息则认为连接断开并关闭连接。

  4. 4. 关闭连接。当客户端或服务器决定关闭连接是会发送一个关闭帧,接收到关闭帧后另一方也会发送一个关闭帧,双方关闭连接。

虽然websocket连接非常高效,避免了频繁创建和关闭连接,但同时维护大量连接会耗费服务器大量内存和CPU资源;需要进一步优化,如使用连接池来管理websocket连接,限制同时打开的连接数避免资源过度消耗;

实现

前端实现

对于Web前端来说,需要先创建WebSocket对象,然后建立连接,并处理好接收/发送数据、错误处理和关闭连接的工作。我们在created阶段就初始化websocket连接。
  1. 1. 创建WebSocket对象

 var url = "ws://127.0.0.1:8899/ws?userid=12345"
 this.websock = new WebSocket(url);
  1. 2. 建立连接

 this.websock.onopen = this.websocketOnopen;
 ...
 websocketOnopenfunction () {
    console.log("WebSocket连接成功");
 }
  1. 3. 发送/接收数据在发送数据这里,WebSocketsend()方法只能发送字符串、二进制数据。要发送json字符串先将对象转换为json字符串再发送。在这里会发送一个typerequest-data,数据为12345的json字符串到服务器中。

 // 接收数据
 websocketOnmessagefunction (e) {
     console.log("- 接收后端消息 -", e.data);
 },
 
 // 发送数据
 websocketSend(text) { 
     const data = "12345"
     try {
         this.websock.send(JSON.stringify({type:'request-data',data}));
     } catch (err) {
         console.log("send failed (" + err.code + ")");
     }
 },
  1. 4. 错误处理

 websocketOnerrorfunction (e) {
   console.log("WebSocket连接发生错误");
   this.reconnect();
 },
  1. 5. 关闭连接/重新连接

 // 关闭连接
 websocketOnclosefunction (e) {
     console.log("connection closed (" + e.code + ")");
     this.reconnect();
 },
  
  // 重新连接
  reconnect() {
     var that = this;
     if (that.lockReconnect) return;
     that.lockReconnect = true;
     setTimeout(function () {
       console.info("重新连接");
       that.initWebSocket();
       that.lockReconnect = false;
     }, 5000);
   },


Gin集成WebSocket


后端实现

Gin框架下实现websocket连接首先需要安装github.com/gorilla/websocket依赖,定义一个WebSocket升级器,新增一个路由并将传入的HTTP请求升级为websocket请求。
  1. 1. 安装依赖

 go get github.com/gorilla/websocket
  1. 2. 定义websocket升级器

 var UpGrader = websocket.Upgrader{
     CheckOrigin: func(r *http.Request) bool { //检查请求来源是否合法,返回true允许所有来源请求升级为websocket
         return true
     },
     ReadBufferSize:  1024// 读取缓冲区大小
     WriteBufferSize: 1024// 写入缓冲区大小
 }
  1. 3. 新增路由并处理websocket请求

 r.GET("/ws", WebSocketHandler)
 
 ..... 
 
 
 func WebSocketHandler(c *gin.Context) {
     userID := c.Query("userid")
     log.Println("userID->", userID)
     // 获取WebSocket连接 下面这行代码使用的方法已经被弃用
     //ws, err := websocket.Upgrade(c.Writer, c.Request, nil, 1024, 1024)
     ws, err := UpGrader.Upgrade(c.Writer, c.Request, nil)
     if err != nil {
         panic(err)
     }
 
     // 处理WebSocket消息
     for {
         messageType, p, err := ws.ReadMessage()
         if err != nil {
             break
         }
 
         fmt.Println("msg:"string(p))
     // 保存连接
     mu.Lock()
         connections[userID] = ws
     mu.Unlock()
 
         err = ws.WriteMessage(messageType, []byte("copy"))
         if err != nil {
             log.Println("websocket write Message ERROR")
         }
     }
 
     // 关闭WebSocket连接
     defer ws.Close()
 }
  1. 4. 维护连接映射

 var connections = make(map[string]*websocket.Conn)

 var mu sync.Mutex


Gin集成WebSocket


写在最后

本人是新手小白,如果这篇笔记中有任何错误或不准确之处,真诚地希望各位读者能够给予批评和指正。谢谢!练习的代码放在这里–↓
https://github.com/FengZeHe/LearnGolang/tree/main/project/WebSocketDemo

原文始发于微信公众号(ProgrammerHe):Gin集成WebSocket

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/207867.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!