Golang使用Socket.io

什么是Socket.IO?

Socket.io是建立在 WebSocket 之上的一个实时应用程序框架。它封装了 WebSocket,并提供了更高级别的接口,
包括实时事件处理、自动重新连接、多房间支持等功能。Socket.IO 在客户端和服务器端分别有对应的库,简化了实时通信的开发。

go

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	socketio "github.com/googollee/go-socket.io"
	"log"
	"net/http"
	"net/url"
	"strings"
)

func main() {
	router := gin.New()
	//初始化server
	server := socketio.NewServer(nil)
	//redis适配器,可选
	ok, err := server.Adapter(&socketio.RedisAdapterOptions{
		Addr:    "127.0.0.1:6379",
		Prefix:  "socket.io",
		Network: "tcp",
	})
	if err != nil || !ok {
		log.Fatal("socket-io adapter error:", err)
	}
	// 建立连接
	server.OnConnect("/", func(s socketio.Conn) error {
		//通过query参数获取建立连接的uid
		params, _ := url.ParseQuery(s.URL().RawQuery)
		uid := params.Get("uid")
		s.SetContext(uid)
		// 加入一个房间
		s.Join("test")
		log.Println("建立连接:", s.ID(), uid) //记录连接错误信息
		return nil
	})

	// 连接错误
	server.OnError("/", func(s socketio.Conn, e error) {
		log.Println("连接错误:", s, e) //记录连接错误信息
	})

	// 关闭连接
	server.OnDisconnect("/", func(s socketio.Conn, reason string) {
		s.LeaveAll() //将socket从所有加入的room中移除
		if uid := s.Context(); uid != nil {
			log.Printf("用户[%s]断开连接", uid)
		}
		log.Println("关闭连接:", s.ID(), reason)
	})

	// ”notice“事件
	server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
		log.Println("notice收到内容::", msg)
		s.Emit("notice", "have "+msg) // 向client回复内容
	})

	router.GET("/bcast", func(context *gin.Context) {
		// 向房间内的所有人员发消息
		server.BroadcastToRoom("/", "test", "notice", "广播通知")
	})

	//----------------------------------end----------------------------------

	go server.Serve()
	defer server.Close()
	router.Use(gin.Recovery(), Cors())
	router.GET("/socket.io/*any", gin.WrapH(server))
	router.POST("/socket.io/*any", gin.WrapH(server))
	router.Static("/public", "./websocket")

	if err := router.Run(":9100"); err != nil {
		log.Fatal("failed run app: ", err)
	}
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method               // 请求方法
		origin := c.Request.Header.Get("Origin") // 请求头部
		var headerKeys []string                  // 声明请求头keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Header("Access-Control-Allow-Origin", origin)                                    // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") // 服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			//  header的类型
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			//              允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")                                                                                                                                                           // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "true")                                                                                                                                                   //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")                                                                                                                                                              // 设置返回格式是json
		}

		// 放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 处理请求
		c.Next() //  处理请求
	}
}

建立websocket文件夹,并新建 index.html


<html lang="cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>WebSocket</title>
<!--    <script type="text/javascript" src="https://cdn.socket.io/4.4.1/socket.io.js"></script>-->
    <script type="text/javascript" src="socket.io.js"></script>
</head>
<body>
<h1> socket.io Client</h1>
<input id="sendTxt" type="text"/>
<button id="sendBtn">发送</button>
<div id="recv"></div>
<script type="text/javascript">

    var socket = io("ws://192.168.252.128:9100?uid=zhangsan");

    //把接收的数据显示到界面
    function showMessage(str){
        var div = document.createElement('div');
        div.innerHTML = str;
        document.body.appendChild(div)
    }

    // 点击之后发送
    document.getElementById("sendBtn").onclick = function(){
        var txt = document.getElementById("sendTxt").value;
        if(txt){        // 文本不为空发送
            socket.emit('notice',txt);
        }
    }

    // 连接成功
    socket.on('connect', function(socket){
        showMessage("连接成功")
    });

    // 连接失败
    socket.on('disconnect', function(socket){
        showMessage("连接失败")
    });

    socket.on('error', function(socket){
        showMessage("连接错误")
    });

    socket.on('notice',function(data){
        console.log("receive server data",data);
        showMessage(data)
    })
</script>
</body>
</html>
posted @   朝阳1  阅读(839)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示