前言

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通信的更多相关文章

  1. golang(gin框架),基于RESTFUL的跨语言远程通信尝试

    golang(gin框架),基于RESTFUL的跨语言远程通信尝试 背景: 在今年的项目实训过程中,遇到了这样的问题: 企业老师讲课实用的技术栈是Java springboot. 实训实际给我们讲课以 ...

  2. 前端程序员学习 Golang gin 框架实战笔记之一开始玩 gin

    原文链接 我是一名五六年经验的前端程序员,现在准备学习一下 Golang 的后端框架 gin. 以下是我的学习实战经验,记录下来,供大家参考. https://github.com/gin-gonic ...

  3. golang Gin framework with websocket

    概述 golang websocket 库 示例 后端 前端 结论 概述 对于 golang 的 web 开发, 之前写过 2 篇 blog, 分别介绍了: 在 Gin 框架下, 各类 http AP ...

  4. golang gin框架中实现一个简单的不是特别精确的秒级限流器

    起因 看了两篇关于golang中限流器的帖子: Gin 开发实践:如何实现限流中间件 常用限流策略--漏桶与令牌桶介绍 我照着用,居然没效果-- 时间有限没有深究.这实在是一个很简单的功能,我的需求是 ...

  5. Golang gin框架学习

    今天开始学习gin框架,在Github上找的示例的go-gin-example, 进度 日期 进展 疑惑 进展 1.30 下拉代码,初步了解gin的介绍.搭建 .mod文件 module原理.使用方法 ...

  6. golang gin框架中实现大文件的流式上传

    一般来说,通过c.Request.FormFile()获取文件的时候,所有内容都全部读到了内存.如果是个巨大的文件,则可能内存会爆掉:且,有的时候我们需要一边上传一边处理. 以下的代码实现了大文件流式 ...

  7. [Golang] Gin框架学习笔记

    0x0 Gin简介 1.Gin 是什么? Gin 是一个用 Go (Golang) 编写的 HTTP web 框架. 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httpr ...

  8. golang gin框架 使用swagger生成api文档

    github地址:https://github.com/swaggo/gin-swagger 1.下载swag $ go get -u github.com/swaggo/swag/cmd/swag ...

  9. golang gin框架中实现"Transfer-Encoding: chunked"方式的分块发送数据到浏览器端

    参考了这篇帖子: https://golangtc.com/t/570b403eb09ecc66b90002d9 golang web如何发送小包的chunked数据 以下是代码: r.GET(&qu ...

  10. golang gin框架设置静态目录

    router := gin.Default() 第一个参数是api 第二个静态问价的文件夹相对目录 router.StaticFS("/data", http.Dir(" ...

随机推荐

  1. IPS 和 IDS

    IPS/IDS 什么是IPS和IDS IDS/IPS是检测和防止对网络服务器进行未授权的访问的系统.有许多产品同时有IDS和IPS的作用,作为加强企业信息安全所必须的系统 什么是IDS(Intrusi ...

  2. 2020-10-04:java中GC Root 对象有哪些?

    福哥答案2020-10-04:#福大大架构师每日一题# 简单回答:1.局部变量.2.静态引用的对象.3.常量引用的对象.4.JNI引用的对象. 中级回答:1.虚拟机栈(栈帧中的本地变量表)中引用的对象 ...

  3. 2022-04-15:给定一个非负数组arr,学生依次坐在0~N-1位置,每个值表示学生的安静值, 如果在i位置安置插班生,那么i位置的安静值变成0,同时任何同学都会被影响到而减少安静值, 同学安静值

    2022-04-15:给定一个非负数组arr,学生依次坐在0~N-1位置,每个值表示学生的安静值, 如果在i位置安置插班生,那么i位置的安静值变成0,同时任何同学都会被影响到而减少安静值, 同学安静值 ...

  4. 2022-03-24:你被请来给一个要举办高尔夫比赛的树林砍树,树林由一个 m x n 的矩阵表示, 在这个矩阵中: 0 表示障碍,无法触碰 1 表示地面,可以行走 比 1 大的数 表示有树的单元格,

    2022-03-24:你被请来给一个要举办高尔夫比赛的树林砍树,树林由一个 m x n 的矩阵表示, 在这个矩阵中: 0 表示障碍,无法触碰 1 表示地面,可以行走 比 1 大的数 表示有树的单元格, ...

  5. 2022-02-19:安装栅栏。 在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。

    2022-02-19:安装栅栏. 在一个二维的花园中,有一些用 (x, y) 坐标表示的树.由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树.只有当所有的树都被绳子包围时,花园才能围好栅栏. ...

  6. Netty实战(一)

    目录 第一章 Java网络编程 1.1 Java NIO 1.2 选择器 第二章 Netty是什么 2.1 Netty简介 2.2 Netty的特性 2.2.1 设计 2.2.2 易于使用 2.2.3 ...

  7. 什么是 Spring?为什么学它?

    前言 欢迎来到本篇文章!在这里,我将带领大家快速学习 Spring 的基本概念,并解答两个关键问题:什么是 Spring,以及为什么学习 Spring. 废话少说,下面,我们开始吧! Spring 官 ...

  8. Springboot 开启异步任务Async,邮件发送任务,定时任务

    异步任务 1.主启动类开启异步注解 2.service目录下开启异步任务注解 @Service public class AsyncService { @Async//异步任务注解的标志 public ...

  9. Cobalt Strike 连接启动教程,制作图片🐎(2)

    扫描有两种方式:arp 和 icmp 查看进程列表 攻击----生成后门-----Payload 可以生成各类语言免杀牧马---(输出:选择C或者python或者php) go.咕.com 生成c语言 ...

  10. OneForAll下载安装以及环境配置

    python-3.9.7-amd64 OneForAll-master python安装以及插件安装 首先下载python解压到电脑c盘在c盘中创建一个工具文件夹,然后下载OneForAll-mast ...