以下内容转载自 https://studygolang.com/articles/30074

前言

最近打算为我的网站添加一个服务器资源监视功能,需要服务端主动向前端推动资源占用数据。这时Http则不能达到要求。所以自然想到采用websocket。

不自量力

以前使用SpringBoot时使用websocket很简单,只需要将ServerEndpointExporter注入到bean容器并配合相应注解即可创建一个websocket服务。这里要感谢各位前辈的封装让我们能尽快实现相应的功能,但本次出于学习目并不是公司项目(效率&稳定性至上)同时使用的开发语言为Golang,其web开发生态也不会像Java那样丰富,所以起初是想自己实现一个websocket服务的,但当我真正查阅websocket协议RFC文档时发现以我现在的水平可能无法顺利完成该项任务。最后还是选择了开源实现gorilla/websocket项目地址

正文

注意:本文所有代码示例均在本人个人网站副本上截取,如果有幸观看本文的不是我自己需要注意实例代码可能无法正常运行因其缺少其他组件特此说明以防耽误大家时间。

添加依赖

本文使用go mod管理依赖

执行go get github.com/gorilla/websocket添加依赖

使用

我们知道websocket由http升级而来,首先会发送附带Upgrade请求头的Http请求,所以我们需要在处理Http请求时拦截请求并判断其是否为websocket升级请求,如果是则调用gorilla/websocket库相应函数处理升级请求。

首相要创建Upgrader实例,该实例用于升级请求

var upgrader = websocket.Upgrader{ReadBufferSize:  1024,WriteBufferSize: 1024,CheckOrigin:     checkOrigin,
}
func checkOrigin(r *http.Request) bool {return true
}

其中CheckOringin是一个函数,该函数用于拦截或放行跨域请求。函数返回值为bool类型,即true放行,false拦截。如果请求不是跨域请求可以不赋值,我这里是跨域请求并且为了方便直接返回true

//Http入口
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {//判断请求是否为websocket升级请求。if websocket.IsWebSocketUpgrade(r) {conn, err := upgrader.Upgrade(w, r, w.Header())} else {//处理普通请求c := newContext(w, r)e.router.handle(c)}
}

此时已经成功升级为websocket连接并获得一个conn实例,之后的发送接收操作皆有conn完成其类型为websocket.Conn。

首先向客户端发送消息使用WriteMessage(messageType int, data []byte),参数1为消息类型,参数2消息内容
示例:

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {//判断请求是否为websocket升级请求。if websocket.IsWebSocketUpgrade(r) {conn, err := upgrader.Upgrade(w, r, w.Header())conn.WriteMessage(websocket.TextMessage, []byte("wxm.alming"))} else {//处理普通请求c := newContext(w, r)e.router.handle(c)}
}

接受客户端消息使用ReadMessage()该操作会阻塞线程所以建议运行在其他协程上。该函数有三个返回值分别是,接收消息类型、接收消息内容、发生的错误当然正常执行时错误为 nil。一旦连接关闭返回值类型为-1可用来终止读操作。
示例:

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {//判断请求是否为websocket升级请求。if websocket.IsWebSocketUpgrade(r) {conn, err := upgrader.Upgrade(w, r, w.Header())conn.WriteMessage(websocket.TextMessage, []byte("wxm.alming"))go func() {for {t, c, _ := conn.ReadMessage()fmt.Println(t, string(c))if t == -1 {return}}}()} else {//处理普通请求c := newContext(w, r)e.router.handle(c)}
}

同时可以为连接设置关闭连接监听,函数为SetCloseHandler(h func(code int, text string) error)函数接收一个函数为参数,参数为nil时有一个默认实现,其源码为:

func (c *Conn) SetCloseHandler(h func(code int, text string) error) {if h == nil {h = func(code int, text string) error {message := FormatCloseMessage(code, "")c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))return nil}}c.handleClose = h
}

可以看到作为参数的函数的参数为int和string类型正好和前端的close(long string)对应即前端调用close(long string)关闭连接后两个参数会被发送给后端并最终被func(code int, text string) error所使用。
示例:

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {//判断请求是否为websocket升级请求。if websocket.IsWebSocketUpgrade(r) {conn, err := upgrader.Upgrade(w, r, w.Header())conn.WriteMessage(websocket.TextMessage, []byte("wxm.alming"))conn.SetCloseHandler(func(code int, text string) error {fmt.Println(code, text)return nil})go func() {for {t, c, _ := conn.ReadMessage()fmt.Println(t, string(c))if t == -1 {return}}}()} else {//处理普通请求c := newContext(w, r)e.router.handle(c)}
}

则断开连接时将打印code和text

注意:要想使断连处理生效必须要有ReadMessage()操作否则不会触发断连处理操作。
以上是常用基础操作点击官方API手册学习更多。

附录:前端测试代码

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><style type="text/css">.body{text-align: center;}#open{width: 120px;height: 35px;}#close{width: 120px;height: 35px;}#text{display: inline-block;margin: auto;margin-top: 10px;margin-bottom: 10px;width: 240px;}</style></head><body class="body"><button id="open">打开连接</button><button id="close">关闭连接</button><br/><input type="text" name="text" id="text" value="" /><br/><button id="send">发送</button><div id="msg"></div></body><script>var openbtn = document.getElementById("open")var closebtn = document.getElementById("close")var text = document.getElementById("text")var send = document.getElementById("send")var msg = document.getElementById("msg")var websocketopenbtn.onclick = function(){websocket = new WebSocket("ws://your ip and port/")websocket.onopen=function(){console.log("connected");}websocket.onmessage = function(e){console.log(e);msg.innerHTML = '接收:'+e.data}websocket.onclose=function(e){console.log("closed",e);}}closebtn.onclick=function(){websocket.close(1000,"close")}send.onclick=function(){var msg = text.valuewebsocket.send(msg)}</script>
</html>

gorilla websocket简易介绍相关推荐

  1. go websocket 关闭_Go实战--使用之gorilla/websocket

    声明不止,继续 go go go!!! 关于websocket,不会陌生. 之前也有博客介绍过golang中使用websocket,其中介绍了两个第三方库: gorilla/websocket nko ...

  2. Go WebSocket开发与测试实践【gorilla/websocket】

    文章引用 Golang 官方标准库实现的 websocket 在功能上有些欠缺,本次介绍的 gorilla/websocket库,是Gorilla出品的速度快.质量高,并且被广泛使用的 websock ...

  3. golang gorilla websocket例子

    WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. WebSocket通信协议于2011年被IETF定 ...

  4. Go实战--Gorilla web toolkit使用之gorilla/websocket

    声明不止,继续 go go go!!! 关于websocket,不会陌生. 之前也有博客介绍过golang中使用websocket,其中介绍了两个第三方库: gorilla/websocket nko ...

  5. gorilla websocket 实例

    以下内容转自自  https://blog.csdn.net/lanyang123456/article/details/83215220 WebSocket协议是基于TCP的一种新的网络协议.它实现 ...

  6. go gorilla_使用gorilla websocket构建浏览器推送通知服务的低级设计

    go gorilla Singhania AdityaSinghania Aditya Follow跟随 Aug 31 8月31 gopher leaving everyone awestruck w ...

  7. WebSocket入门介绍及编程实战

    前言:最近看了几天的WebSocket,从以前的只闻其名,到现在也算是有一点点的了解了.所以就准备用博客记录一下自己的学习过程,希望也能帮助其它学习的人,因为我本人学习的过程中也是参考了很多其它人的博 ...

  8. 传统公司部署OpenStack(t版)简易介绍(九)——控制台部署

    传统公司部署OpenStack(t版)简易介绍(九)--控制台部署 一.创建flat外部网络.创建内部交换网络.创建项目路由 二.上传cirros镜像 三.创建实例类型 四.创建实例.打通内外网 一. ...

  9. 传统公司部署OpenStack(t版)简易介绍(八)——Dashboard模块部署

    传统公司部署OpenStack(t版)简易介绍(八)--Dashboard模块部署 一.安装服务(c1) 二.重启服务(c1) 三.重启 ct 节点的 memcache 服务 四.验证操作 一.安装服 ...

最新文章

  1. GIS项目中数据开源、工具开源、开发开源的解决方案
  2. java volatile 用法_java关键字volatile用法详解
  3. java兩個矩陣相乘_Day12 練習java-矩陣乘法
  4. Hive学习笔记 —— Hive的数据类型
  5. 如何用 C++ 在 10 行内写出八皇后?
  6. Linux系统入门之如何安装Linux系统
  7. 17_clickhouse分布式集群部署
  8. redux中间件之redux-thunk
  9. 送书!1991-2018,区块链的那点事,都在这里了!
  10. 湖南第一师范计算机科学与技,湖南第一师范学院2019年各省各专业录取分数线...
  11. 物权法全文内容有哪些呢-广告外链_SEO优化的站外优化工作有哪些?
  12. 使用 requests 进行身份认证
  13. 十天学会php之第九天
  14. 网站优化关键词选择时需要的注意事项
  15. 如何用python编写财务记账软件_Python实现简单的记账本功能
  16. 30系显卡安装tensorflow-gpu1.15
  17. vw/vh:移动适配之vw/vh(使用方法)
  18. JVM笔记十四:方法区
  19. 快给你的对象做一个微信公众号播报吧-java版
  20. AI测试中的数据收集

热门文章

  1. SpringBoot应用WebSocket实现在线聊天
  2. 前端比较好用的一个Flex布局样式包
  3. VC++中遇到的错误“Error spawning cl.exe”
  4. 阿里云服务器支持IPV6和CND的详细教程
  5. layui标签页切换并自动刷新
  6. MP4/MPEG4/3GP转换软件至尊---《MP4/RM转换专家》小记
  7. 论文中出现的 cf. i.e. s.t. e.g. w.r.t. et al. etc等英文缩写是什么意思
  8. window server 2012 更改密钥 更改系统序列号
  9. SpringBoot+log4j2.xml读取application.yml属性值
  10. 骨传导耳机有什么危害?骨传导耳机对人体有什么影响?