go-zero和WebSocket 使用

前言:

七牛云 Go 模块代理。 https://goproxy.cn/ 解决包下载问题

WebSocket

Go语言标准套件里面没有提供对WebSocket的支持,但是在由官方维护的go.net子套件中有对这个的支持,你可以透过如下的命令取得该套件:

go get -u golang.org/x/net/websocket
type  WebSocket  struct {
}

func (ws *WebSocket) ServerWs(w http.ResponseWriter, r *http.Request) {
	websocket.Server{Handler: ws.Handler}.ServeHTTP(w, r)
}

func (sw *WebSocket) Handler(ws *websocket.Conn) {
	webSocketClient := sw.AddClinetJson(ws, "", 0)
	webSocketClient.Start()
}

go-zero

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。
go-zero官网

go get -u github.com/zeromicro/go-zero@latest

go-zero 使用gorilla/websocket示例
https://github.com/zeromicro/zero-examples/blob/main/chat/main.go

Actor

Actor模型介绍
gonet 游戏服务器架构
每个Actor都是一个独立的计算实体,Actor之间不共享数据,各个Actor只能操作自己的数据,所有的交互全部通过传递消息的方式进行,可以有效避免共享数据带来的并发竞争问题。

服务端示例代码

base.go

package base
import (
	"github.com/erdong01/kit/actor"
	"github.com/erdong01/kit/network"
)
var SERVER *MessageMrg

type MessageMrg struct {
	actor.Actor
	*network.WebSocket
}

main.go

package main

import (
 "flag"
 "fmt"
 "net/http"
 "marstm/applet/internal/config"
 "marstm/applet/internal/handler"
 "marstm/applet/internal/handler/base"
 "marstm/applet/internal/svc"
 "github.com/erdong01/kit/network"
 "github.com/zeromicro/go-zero/core/conf"
 "github.com/zeromicro/go-zero/rest"
)

var configFile = flag.String("f", "applet/etc/applet-api.yaml", "the config file")

func main() {
	flag.Parse()
	var c config.Config
	conf.MustLoad(*configFile, &c)
	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()
	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)
	server.AddRoute(rest.Route{
		Method: http.MethodGet,
		Path:   "/",
		Handler: func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path != "/" {
				http.Error(w, "Not found", http.StatusNotFound)
				return
			}
			if r.Method != "GET" {
				http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
				return
			}
			http.ServeFile(w, r, "home.html")
		},
	})
	handler.Init()
	server.AddRoute(rest.Route{
		Method: http.MethodGet,
		Path:   "/ws",
		Handler: func(w http.ResponseWriter, r *http.Request) {
			base.SERVER.WebSocket.ServerWs(w, r)
		},
	})
	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()
}

handler.go

package handler

import (
	"context"
	"fmt"
	"marstm/api"
	"marstm/applet/internal/handler/base"
	kitApi "github.com/erdong01/kit/api"
	"github.com/erdong01/kit/network"
)

type Handler struct {
	*base.MessageMrg
}

func (a *Handler) GetHead(ctx context.Context) kitApi.JsonHead {
	rpcHead := ctx.Value("Head").(kitApi.JsonHead)
	return rpcHead
}
// 初始化
func Init() {
	base.SERVER = &base.MessageMrg{}
	base.SERVER.Actor.Init()
	var this Handler
	this.MessageMrg = base.SERVER
	base.SERVER.RegisterCall("2000", this.Connect) // 业务方法注册
	base.SERVER.Actor.Start()
	base.SERVER.WebSocket = &network.WebSocket{}
	base.SERVER.WebSocket.Init("", 9797)	base.SERVER.WebSocket.BindPacketFuncJson(base.SERVER.PacketFuncJson)
}
// 客户链接
func (h *Handler) Connect(ctx context.Context, req *api.ConnectReq) {
	head := h.GetHead(ctx)
	client :=    base.SERVER.WebSocket.GetClientById(head.SocketId)
		client.SendJson(kitApi.JsonHead{}, "2000", "链接成功", "test")
}

微信小程序

App.js

App({
	webSocketUrl: "ws://127.0.0.1:9696/ws",
	globalData: {
        socketOpen: false,
        SocketTask: {},
        SocketTimeId: 0,
    },
	openSocket() {
		var that = this
        that.SocketTask = wx.connectSocket({
			url: that.webSocketUrl
        })
        //打开时的动作
        that.SocketTask.onOpen(() => {
			console.log('WebSocket 已连接')
            that.socketOpen = true
            var session_key = wx.getStorageSync('session_key')
            that.sendSocketMessage({
                "FuncName":"2000",
                "Data":{"token":session_key}
            })
            that.SocketTimeId = setInterval(that.sendSocketMessage, 10000)
        })
        //断开时的动作
        that.SocketTask.onClose(() => {
            console.log("WebSocket 已断开")
            that.socketOpen = false
            clearInterval(that.SocketTimeId)
        })
        //报错时的动作
        that.SocketTask.onError(error => {
            console.error('socket error:', error)
        })
    },

    sendSocketMessage(msg) {
        if (this.socketOpen) {
            if (msg == undefined) {
                msg = {}
            }
            var s = JSON.stringify(msg);
            this.SocketTask.send({
                data: s
            })
        }
    },

    closeSocket() {
		var that = this
        that.SocketTask.close({
            success: () => {
				that.socketOpen = false
				clearInterval(that.SocketTimeId)
            }
        });
    },
})

测试

go服务端:

Apifox客户端:

posted @ 2023-06-08 20:48  耳东01  阅读(1393)  评论(0)    收藏  举报