go-zero和WebSocket 使用
前言:
七牛云 Go 模块代理。 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示例
github.com/zeromicro/zero-examples...
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客户端:
本作品采用《CC 协议》,转载必须注明作者和本文链接
你这套代码是把重要的原理都包装到你的kit库里,然后给大家看脚手架吗?