[golang]gin框架接收websocket通信
前言
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket让客户端和服务端之间的数据交换变得非常简单,且允许服务器主动向客户端推送数据,并且之后客户端和服务端所有的通信都依靠这个专用协议进行。
本文使用gin框架编写服务端应用,配置路由接收websocket请求并处理。同时实现一个websocket命令行客户端用于与服务端通信。
服务端
下面代码示例中,使用gin创建一个应用,并将自定义函数WebSocketHandler()注册到/ws路由。WebSocketHandler()功能非常简单,客户端发送什么就原样返回什么。
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
func WebSocketHandler(c *gin.Context) {
// 获取WebSocket连接
wsUpgrader := websocket.Upgrader{
HandshakeTimeout: time.Second * 10,
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
ws, err := wsUpgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
// 处理WebSocket消息
for {
messageType, p, err := ws.ReadMessage()
if err != nil {
fmt.Println(err)
return
}
switch messageType {
case websocket.TextMessage:
fmt.Printf("处理文本消息, %s\n", string(p))
ws.WriteMessage(websocket.TextMessage, p)
// c.Writer.Write(p)
case websocket.BinaryMessage:
fmt.Println("处理二进制消息")
case websocket.CloseMessage:
fmt.Println("关闭websocket连接")
return
case websocket.PingMessage:
fmt.Println("处理ping消息")
ws.WriteMessage(websocket.PongMessage, []byte("ping"))
case websocket.PongMessage:
fmt.Println("处理pong消息")
ws.WriteMessage(websocket.PongMessage, []byte("pong"))
default:
fmt.Printf("未知消息类型: %d\n", messageType)
return
}
}
}
func NewServer() *gin.Engine {
gin.SetMode(gin.DebugMode) // 设置运行模式
gin.DisableConsoleColor() // 禁用控制台输出的颜色
router := gin.Default()
return router
}
func main() {
// 创建Gin应用
app := NewServer()
// 注册WebSocket路由
app.GET("/ws", WebSocketHandler)
// 启动应用
err := app.Run("127.0.0.1:8080")
if err != nil {
panic(err)
}
}
客户端
写个了命令行客户端用于连接websocket服务端,接收键盘输入,然后发送到服务端。使用flag解析命令行参数用于配置服务端连接。
package main
import (
"flag"
"fmt"
"log"
"net/http"
"net/url"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/websocket"
)
var (
Addr string
Path string
Token string
)
func init() {
flag.StringVar(&Addr, "addr", "localhost:8080", "WebSocket 服务器地址")
flag.StringVar(&Path, "path", "/ws", "WebSocket接口路由")
flag.StringVar(&Token, "token", "123456", "连接 WebSocket 服务器的令牌")
flag.Parse()
}
func main() {
header := make(http.Header)
header.Set("token", Token)
u := url.URL{Scheme: "ws", Host: Addr, Path: "/ws"}
conn, _, err := websocket.DefaultDialer.Dial(u.String(), header)
if err != nil {
log.Fatalf("连接 WebSocket 服务器失败:%v", err)
return
}
defer conn.Close()
// 创建channel用于监听操作系统的中断信号
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
response := make(chan string, 8)
defer close(response)
// 启动一个 goroutine 用于接收 WebSocket 服务器的响应
go func(resp chan string) {
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Printf("server> ERROR! %v\n", err)
return
}
resp <- string(message)
}
}(response)
// 读取用户的键盘输入,并发送到 WebSocket 服务器
for {
select {
case <-interrupt: // 等待中断信号
log.Println("收到中断信号,关闭 WebSocket 连接 ...")
err := conn.WriteMessage(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Printf("发送关闭消息失败:%v\n", err)
}
<-interrupt // 关闭websocket连接之前, 确保已经发送到服务端的消息能够被确认和处理
return
default:
var input string
fmt.Printf("%s client> ", time.Now().Format("2006-01-02 15:04:05"))
fmt.Scanln(&input)
if input == "exit" {
log.Println("用户输入 exit, 关闭 WebSocket 连接 ...")
err := conn.WriteMessage(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Printf("发送关闭消息失败:%v", err)
return
}
return
}
if len(input) == 0 {
log.Println("输入消息为空")
continue
}
err := conn.WriteMessage(websocket.TextMessage, []byte(input))
if err != nil {
log.Printf("发送消息失败:%v", err)
continue
}
// 阻塞等待服务端响应
resp := <-response
log.Printf("server> %s\n", resp)
}
}
}
参考
[golang]gin框架接收websocket通信的更多相关文章
- golang(gin框架),基于RESTFUL的跨语言远程通信尝试
golang(gin框架),基于RESTFUL的跨语言远程通信尝试 背景: 在今年的项目实训过程中,遇到了这样的问题: 企业老师讲课实用的技术栈是Java springboot. 实训实际给我们讲课以 ...
- 前端程序员学习 Golang gin 框架实战笔记之一开始玩 gin
原文链接 我是一名五六年经验的前端程序员,现在准备学习一下 Golang 的后端框架 gin. 以下是我的学习实战经验,记录下来,供大家参考. https://github.com/gin-gonic ...
- golang Gin framework with websocket
概述 golang websocket 库 示例 后端 前端 结论 概述 对于 golang 的 web 开发, 之前写过 2 篇 blog, 分别介绍了: 在 Gin 框架下, 各类 http AP ...
- golang gin框架中实现一个简单的不是特别精确的秒级限流器
起因 看了两篇关于golang中限流器的帖子: Gin 开发实践:如何实现限流中间件 常用限流策略--漏桶与令牌桶介绍 我照着用,居然没效果-- 时间有限没有深究.这实在是一个很简单的功能,我的需求是 ...
- Golang gin框架学习
今天开始学习gin框架,在Github上找的示例的go-gin-example, 进度 日期 进展 疑惑 进展 1.30 下拉代码,初步了解gin的介绍.搭建 .mod文件 module原理.使用方法 ...
- golang gin框架中实现大文件的流式上传
一般来说,通过c.Request.FormFile()获取文件的时候,所有内容都全部读到了内存.如果是个巨大的文件,则可能内存会爆掉:且,有的时候我们需要一边上传一边处理. 以下的代码实现了大文件流式 ...
- [Golang] Gin框架学习笔记
0x0 Gin简介 1.Gin 是什么? Gin 是一个用 Go (Golang) 编写的 HTTP web 框架. 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httpr ...
- golang gin框架 使用swagger生成api文档
github地址:https://github.com/swaggo/gin-swagger 1.下载swag $ go get -u github.com/swaggo/swag/cmd/swag ...
- golang gin框架中实现"Transfer-Encoding: chunked"方式的分块发送数据到浏览器端
参考了这篇帖子: https://golangtc.com/t/570b403eb09ecc66b90002d9 golang web如何发送小包的chunked数据 以下是代码: r.GET(&qu ...
- golang gin框架设置静态目录
router := gin.Default() 第一个参数是api 第二个静态问价的文件夹相对目录 router.StaticFS("/data", http.Dir(" ...
随机推荐
- selenium控制文件下载位置
selenium控制文件下载位置 我们在自动化下载文件的时候势必存在一种需求: 通过chrome将文件保存到指定位置 1. google窗口实现 配置'prefs'将文件下载到指定位置, 并通过判 ...
- Git&GitHub简介与入手(一)
一.Git版本控制 1.集中式版本控制工具:SVN(版本控制集中在服务器端,会有单点故障风险): 2.分布式版本控制工具:Git: 3.Git简史 Talk is cheap, show me the ...
- 2022-03-31:有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱, 以及不同程度的安静值(quietness) 为了方便起见,我们将编号为 x 的人简称为
2022-03-31:有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱, 以及不同程度的安静值(quietness) 为了方便起见,我们将编号为 x 的人简称为 ...
- Selenium - 元素操作(5) - iframe切换
Selenium - 元素操作 iframe切换 很多时候定位元素时候总是提示元素定位不到的问题,明明元素就在那里,这个时候就要关注你所 定位的元素是否在frame和iframe里面: frame标签 ...
- vue全家桶进阶之路36:Vue3 全局路由useRouter和本地路由useRoute
在 Vue.js 3.x 中,我们可以使用 useRouter 和 useRoute 来获取当前路由对象和当前路由信息. useRouter useRouter 可以用来获取当前路由对象.我们可以通过 ...
- CMD 常用命令总结
CMD 常用命令总结 小技巧: 输入 help,查看帮助: Tab 键,自动补全: 上/下方向键,查看历史命令: 右键窗口标题栏 -> 属性,可以修改外观样式. # 关机.重启.注销.休眠.定时 ...
- [安全开发] SQL注入扫描(一股子GPT味~)
实际上大部分都是它写的,它真我哭 SQL注入扫描就是一种用于检测和预防SQL注入攻击的工具.它通过模拟SQL注入攻击的方式,向目标网站发送特定的SQL查询语句,以验证目标网站是否存在SQL注入漏洞.S ...
- 从 0 到 1 搭建自己的脚手架(java 后端)
一.脚手架是什么 脚手架是一种基础设施工具,用于快速生成项目的框架代码和文件结构.它是一种标准化的开发工具,使开发人员能够在项目的早期阶段快速搭建出一个具备基本功能和结构的系统. 二.脚手架的意义 主 ...
- ENVI5.3 安装教程,新手入门(超详细)附安装包和常见问题
ENVI是一个完整的遥感图像处理平台,广泛应用于科研.环境保护.气象.农业.林业.地球科学.遥感工程.水利.海洋等领域.目前ENVI已成为遥感影像处理的必备软件,包含辐射定标.大气校正.镶嵌裁剪.分类 ...
- C++面试八股文:static和const的关键字有哪些用法?
某日二师兄参加XXX科技公司的C++工程师开发岗位第7面: 面试官:C++中,static和const的关键字有哪些用法? 二师兄:satic关键字主要用在以下三个方面:1.用在全局作用域,修饰的变量 ...