首页 > 其他分享 >[golang]gin框架接收websocket通信

[golang]gin框架接收websocket通信

时间:2023-05-27 19:56:16浏览次数:55  
标签:websocket err WebSocket fmt golang ws gin

前言

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)
		}
	}
}

参考

标签:websocket,err,WebSocket,fmt,golang,ws,gin
From: https://www.cnblogs.com/XY-Heruo/p/17437232.html

相关文章

  • springboot整合websocket
    一、引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId&g......
  • AtCoder Beginner Contest 298(D,F)
    AtCoderBeginnerContest298(D,F)D(思维,模拟,快速幂)D大意是最初有一个数字\(1\),然后进行\(q\)个操作有三种操作\(1\),输入\(1,x\),在原来的数字后面添加一个尾数,例如原本的数是\(12\),输入了\(15\),数字变成了\(125\)\(2\),输入\(2\),把原来的数字第一位数删除,例如原本的数是......
  • Unity中的RegisterPlugins:深入解析与实用案例
    Unity中的RegisterPlugins:深入解析与实用案例在Unity游戏开发中,我们经常需要使用第三方插件来实现一些特定的功能。为了让这些插件能够在Unity中正常工作,我们需要对它们进行注册。本文将详细介绍Unity中的RegisterPlugins方法,并通过三个实用案例来展示其强大的功能。什么是Regist......
  • AtCoder Beginner Contest 299(E,F)
    AtCoderBeginnerContest299(E,F)E(最短路)E题目大意为有\(n\)个点和\(m\)条边,我们我个这些点匹配颜色(有两种颜色),但是要满足下面的条件必须由一个点的颜色是\(1\)然后给出\(k\)点限制对于\(p_i\)这一个点,离他最近的一个颜色为\(1\)的点的最近距离为\(d_i\)既然知道某个点......
  • Nginx配置Basic_Auth登录认证
    一般来说,僵尸网络的扫描行为都是全互联网大范围进行的,并且所探测的漏洞大多都是一些新爆发的cms漏洞(ThinkPHP)、或者是一些常见的框架组件漏洞(如Struts2),针对该特性,我们可以配置BasicAuth登录认证(ngx_http_auth_basic_module),来减少僵尸网络对我们web服务的侵扰。注:BasicAuth......
  • nginx代理给网关时 丢失请求的host信息问题
    nginx搭建域名访问环境描述:访问gulimall.com,Nginx反向代理到网关地址,然后网关转发到具体的product服务域名映射的效果如下:具体步骤:(1)hosts文件配置域名和ip映射修改windows下host文件:C:\Windows\System32\drivers\etc\hosts为了方便,可以使用SwitchHost工具(2)配置nginx......
  • 使用SpringMVC 拦截器导致出现@CrossOrigin失效问题解决办法
    非简单请求会发起一个OPTIONS方法的预检请求,这个请求会被拦截器拦截,但是服务器没有给浏览器返回必要的跨域指示信息(比如:“Access-Control-Allow-Origin”----允许哪些请求访问),浏览器没收到指示信息,就认为服务器不允许跨域请求,就会报错。所以需要在拦截器拦截OPTIONS方法的预......
  • pongo2 类似django 语法的golang 模版引擎
    pongo2类似django语法的golang模版引擎,当前兼容django1.7同时还包含了强大的三方生态支持(比如beego,gin,echo框架。。。)参考使用main.gopackagemain import("fmt""log" "github.com/flosch/pongo2/v6") funcmain(){tpl,e......
  • golang中切片越界获取到零值的坑
    B站视频演示golang中切片越界获取到零值的坑代码截图~~~......
  • Hugging News #0526: Hugging Cast 发布第一期、邀请来认领自己的论文啦!
    每一周,我们的同事都会向社区的成员们发布一些关于HuggingFace相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「HuggingNews」,本期HuggingNews有哪些有趣的消息,快来看看吧!重磅更新HuggingCast播客#1发布Hugg......