给Go的Gin web框架增加 WebSocket 功能,让WebSocket 更好用

简介: 给Go的Gin web框架增加 WebSocket 功能,让WebSocket 更好用

Gin 是一个 go 的 web 框架,它具有轻量级,高性能,运行速度快,分组的路由器,良好的崩溃捕获和错误处理,非常好的支持中间件,rest api和json。


总之在 Go语言开发领域是一款值得好好研究的 Web 框架。官方地址:https://github.com/gin-gonic/gin


但是最近想尝试下websocket功能,发现Gin框架里没有。


Go 官方没有提供对 WebSocket 的支持,必须选择第三方提供的包。


常用的有两种,golang.org/x/net/websocket和 https://github.com/gorilla/websocket


《Go Web 编程》一书中的例子使用的是golang.org/x/net/websocket


其中gorilla/websocket更常用些,Apache的Paho GO mqtt client库中和go的另外一个web框架iris中,就使用的是gorilla/websocket库。


是不是直接把gorilla/websocket引入进gin框架就可以了?


但是还得需要自己完成封装,若不花功夫封装好,不是很好用,稳定性更难保证。


网上找到gin中使用gorilla的websocket库的例子,都只是一些简单的测试,一点儿都不好用。


接下来,为了让websocket在gin中更好用些,移植iris框架中的websocket功能到gin框架中,使用起来就简单啦,使用如下:


github 地址: https://github.com/yangyongzhen/gin-websocket.git


package main
import (
  "fmt"
  //"github.com/gin-contrib/cors"
  "github.com/gin-gonic/gin"
  "net/http"
  "strings"
  "websockTest/websocket"
)
func main() {
  ws := websocket.New(websocket.Config{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
  })
  ws.OnConnection(handleConnection)
  r := gin.Default()
  //允许跨域
  //config := cors.DefaultConfig()
  //config.AllowOrigins = []string{"http://127.0.0.1:9090"}
  //r.Use(Cors())
  //静态资源
  r.Static("/static", "./static")
  r.LoadHTMLGlob("views/*")
  r.GET("/api/v3/device", ws.Handler())
  r.GET("/test", func(c *gin.Context) {
    c.HTML(http.StatusOK, "test.html", gin.H{
      "title": "this is a test",
    })
  })
  r.Run(":9090")
}
func handleConnection(c websocket.Connection) {
  fmt.Println("client connected,id=", c.ID())
  c.Write(1, []byte("welcome client"))
  // 测试从浏览器中读取事件
  c.On("chat", func(msg string) {
    // 将消息打印到控制台
    fmt.Printf("%s sent: %s\n", c.Context().ClientIP(), msg)
    // 将消息写回客户端消息所有者:
    // c.Emit("chat", msg)
    c.To(websocket.All).Emit("chat", msg)
  })
  c.OnMessage(func(msg []byte) {
    fmt.Println("received msg:", string(msg))
    c.Write(1, []byte("hello aa"))
    c.To(websocket.All).Emit("chat", msg)
  })
  c.OnDisconnect(func() {
    fmt.Println("client Disconnect,id=", c.ID())
  })
}


附,网上找到的一些测试代码如下:


package server
import (
  "fmt"
  "net"
  "net/http"
  "time"
  "github.com/gorilla/websocket"
)
const (
  // Time allowed to write a message to the peer.
  writeWait = 10 * time.Second
  // Maximum message size allowed from peer.
  maxMessageSize = 8192
  // Time allowed to read the next pong message from the peer.
  pongWait = 60 * time.Second
)
type WsServer struct {
  listener net.Listener
  addr     string
  upgrade  *websocket.Upgrader
}
func NewWsServer() *WsServer {
  ws := new(WsServer)
  ws.addr = "0.0.0.0:9090"
  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
}
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)
    fmt.Println("path error,url=", r.URL.Path)
    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)
}
func (self *WsServer) connHandle(conn *websocket.Conn) {
  defer func() {
    conn.Close()
  }()
  stopCh := make(chan int)
  go self.send(conn, stopCh)
  conn.SetReadLimit(maxMessageSize)
  conn.SetReadDeadline(time.Now().Add(pongWait))
  conn.SetPongHandler(func(string) error {
    fmt.Println("this is PongHandler")
    conn.SetReadDeadline(time.Now().Add(pongWait))
    if err := conn.WriteMessage(websocket.PongMessage, nil); err != nil {
      fmt.Println("resp pong error", err)
    } else {
      fmt.Println("resp pong ok")
    }
    return nil
  })
  for {
    conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(60000)))
    _, msg, err := conn.ReadMessage()
    if err != nil {
      // 判断是不是超时
      if netErr, ok := err.(net.Error); ok {
        if netErr.Timeout() {
          fmt.Printf("ReadMessage timeout remote: %v\n", conn.RemoteAddr())
          close(stopCh)
          return
        }
      }
      // 其他错误,如果是 1001 和 1000 就不打印日志
      if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) {
        fmt.Printf("ReadMessage other remote:%v error: %v \n", conn.RemoteAddr(), err)
      }
      //close(stopCh)
      return
    }
    fmt.Println("收到消息:", string(msg))
  }
}
//测试一次性发送 10万条数据给 client, 如果不使用 time.Sleep browser 过了超时时间会断开
func (self *WsServer) send10(conn *websocket.Conn) {
  for i := 0; i < 1; i++ {
    data := fmt.Sprintf("hello websocket test from server %v,count=%d", time.Now().UnixNano(), i+1)
    err := conn.WriteMessage(1, []byte(data))
    if err != nil {
      fmt.Println("send msg faild ", err)
      return
    }
    //time.Sleep(time.Millisecond * 1)
  }
}
func (self *WsServer) send(conn *websocket.Conn, stopCh chan int) {
  self.send10(conn)
  for {
    select {
    case <-stopCh:
      fmt.Println("connect closed")
      return
      // case <-time.After(time.Second * 1):
      //  fmt.Println("time after....")
    }
  }
}
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
}


相关文章
|
5天前
|
前端开发 JavaScript 网络协议
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
【7月更文挑战第18天】前后端分离采用Flask/Django框架,前端JavaScript框架如Vue.js与后端通过AJAX/Fetch通信。WebSocket提供实时双向通信,Python可借助websockets库或Flask-SocketIO实现。最佳实践包括定义清晰的接口规范,确保安全性(HTTPS,认证授权),优化性能,和健壮的错误处理。结合两者,打造高效实时应用。
20 1
|
1天前
|
开发框架 JSON API
震撼发布!Python Web开发框架下的RESTful API设计全攻略,让数据交互更自由!
【7月更文挑战第22天】在Python Web开发中,设计高效的RESTful API涉及选择框架(如Flask或Django)、明确资源及使用HTTP方法(GET, POST, PUT, DELETE)来操作数据。响应格式通常是JSON,错误处理也很重要。示例展示了使用Flask创建图书管理API,包括版本控制、文档化、安全性和性能优化是最佳实践。这样的API使数据交互更顺畅。
14 2
|
6天前
|
前端开发 JavaScript API
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
【7月更文挑战第17天】现代Web开发趋势中,前后端分离配合WebSocket满足实时通信需求。Django Channels扩展了Django,支持WebSocket连接和异步功能。通过安装Channels、配置设置、定义路由和消费者,能在Django中实现WebSocket交互。前端使用WebSocket API连接后端,实现双向数据流,如在线聊天功能。集成Channels提升Web应用的实时性和用户体验,适应实时交互场景的需求。**
28 6
|
2天前
|
移动开发 小程序 JavaScript
转Web运行时的“框架”模块主要负责什么功能
转Web运行时的“框架”模块主要负责什么功能
|
5天前
|
前端开发 Python
前后端分离的进化:Python Web项目中的WebSocket实时通信解决方案
【7月更文挑战第18天】在Python的Flask框架中,结合Flask-SocketIO库可轻松实现WebSocket实时通信,促进前后端分离项目中的高效交互。示例展示了一个简单的聊天应用:Flask路由渲染HTML,客户端通过Socket.IO库连接服务器,发送消息并监听广播。此方法支持多种实时通信协议,适应不同环境,提供流畅的实时体验。
19 3
|
4天前
|
JSON 中间件 数据处理
实践出真知:通过项目学习Python Web框架的路由与中间件设计
【7月更文挑战第19天】探索Python Web开发,掌握Flask或Django的关键在于理解路由和中间件。路由连接URL与功能,如Flask中@app.route()定义请求响应路径。中间件在请求处理前后执行,提供扩展功能,如日志、认证。通过实践项目,不仅学习理论,还能提升构建高效Web应用的能力。示例代码展示路由定义及模拟中间件行为,强调动手实践的重要性。
|
4天前
|
JSON 中间件 Go
Go语言Web框架Gin介绍
【7月更文挑战第19天】Gin是一个功能强大、高性能且易于使用的Go语言Web框架。它提供了路由、中间件、参数绑定等丰富的功能,帮助开发者快速构建高质量的Web应用。通过本文的介绍,你应该对Gin框架有了初步的了解,并能够使用它来开发简单的Web服务。随着你对Gin的深入学习和实践,你将能够利用它构建更复杂、更强大的Web应用。
|
2天前
|
API 网络架构 开发者
探索Python Web框架的核心:路由机制详解
【7月更文挑战第21天】Python Web开发中,Flask和Django的路由机制解析:Flask用@app.route装饰器绑定URL到视图,如`@app.route(&#39;/user/&lt;username&gt;&#39;)`;Django通过urls.py配置URL模式,如`path(&#39;user/&lt;str:username&gt;/&#39;, views.user_profile, name=&#39;user_profile&#39;)`。两者都支持静态、动态路由和HTTP方法绑定,展现路由灵活性,助力构建高效Web应用。
8 0
|
2天前
|
缓存 监控 安全
中间件在Python Web框架中的角色与应用场景
【7月更文挑战第21天】中间件在Python Web开发中作为服务器与应用间的软件层,拦截、处理请求和响应,无需改动应用代码。它扩展框架功能,复用跨应用逻辑,加强安全,优化性能。如Django中间件处理请求/响应,Flask通过WSGI中间件实现类似功能,两者均在不触及核心代码前提下,灵活增强应用行为,是现代Web开发关键组件。
|
3天前
|
前端开发 开发者 Python
从零到一:Python Web框架中的模板引擎入门与进阶
【7月更文挑战第20天】模板引擎如Jinja2在Python Web开发中连接后端与前端,提高代码可读性和协作效率。Flask默认集成Jinja2,提供条件语句、循环、宏和模板继承等功能。例如,创建一个简单Flask应用,渲染&quot;Hello, World!&quot;,并展示如何使用条件语句和循环处理数据。通过宏定义重用代码,模板继承实现页面结构共享。学习模板引擎能提升开发效率和项目质量。
13 0

热门文章

最新文章