From 605197345b84f99f30b8a4c71878160affa2ce33 Mon Sep 17 00:00:00 2001
From: BuildingBlocksLin <835606593@qq.com>
Date: Sat, 28 Jun 2025 17:38:22 +0800
Subject: [PATCH] =?UTF-8?q?=E7=BD=91=E7=BB=9C=E5=B1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Client/a.html | 175 ------------------
Client/web/game.js | 103 +++++++++++
Client/web/index.html | 17 ++
Client/web/style.css | 80 ++++++++
Server/Gateway/app/app.go | 15 +-
Server/Gateway/app/websocket.go | 2 +-
Server/Gateway/config/config.dev.yaml | 22 ++-
Server/Gateway/config/config.go | 33 ++--
Server/Gateway/go.mod | 12 +-
Server/Gateway/go.sum | 12 --
Server/Gateway/handler/ws_handler/client.go | 120 +++++++-----
Server/Gateway/handler/ws_handler/event.go | 9 +-
Server/Gateway/handler/ws_handler/temp.go | 21 +++
Server/Gateway/net/ws_gateway/server.go | 40 +++-
Server/common/log/log_zap.go | 2 +-
Server/common/net/socket/server.go | 20 +-
.../common/net/socket/websocket/websocket.go | 40 ++--
Server/common/net/socket/websocket/wsconn.go | 100 +++-------
Server/common/proto/cs/define.proto | 22 +++
Server/common/utils/number.go | 13 ++
20 files changed, 482 insertions(+), 376 deletions(-)
delete mode 100644 Client/a.html
create mode 100644 Client/web/game.js
create mode 100644 Client/web/index.html
create mode 100644 Client/web/style.css
create mode 100644 Server/Gateway/handler/ws_handler/temp.go
create mode 100644 Server/common/proto/cs/define.proto
create mode 100644 Server/common/utils/number.go
diff --git a/Client/a.html b/Client/a.html
deleted file mode 100644
index a2f6d24..0000000
--- a/Client/a.html
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-
-
-
- 游戏方块容器
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Client/web/game.js b/Client/web/game.js
new file mode 100644
index 0000000..fcd4cd9
--- /dev/null
+++ b/Client/web/game.js
@@ -0,0 +1,103 @@
+const { createApp } = Vue;
+
+const App = {
+ template: `
+
+ `,
+ data() {
+ return {
+ squares: [
+ { connected: false, ws: null },
+ { connected: false, ws: null },
+ { connected: false, ws: null },
+ { connected: false, ws: null }
+ ]
+ }
+ },
+ mounted() {
+ // 为每个正方形建立独立的WebSocket连接
+ this.squares.forEach((square, index) => {
+ this.connectWebSocket(square, index);
+ });
+ },
+ methods: {
+ connectWebSocket(square, index) {
+ // 替换为实际的WebSocket服务器地址
+ const wsUrl = `ws://localhost:8501/?token=${index + 1}`;
+
+ try {
+ square.ws = new WebSocket(wsUrl);
+
+ square.ws.onopen = () => {
+ square.connected = true;
+ console.log(`WebSocket ${index + 1} connected`);
+
+ // 连接建立后发送初始消息
+ try {
+ square.ws.send(JSON.stringify({
+ type: "init"
+ }));
+ console.log(`Initial message sent to WebSocket ${index + 1}`);
+ } catch (error) {
+ console.error(`Failed to send initial message to WebSocket ${index + 1}:`, error);
+ }
+ };
+
+ square.ws.onclose = (e) => {
+ square.connected = false;
+ console.log(`WebSocket ${index + 1} disconnected`);
+ console.log(e.code, e.reason, e.wasClean)
+ // 尝试重新连接
+ // setTimeout(() => this.connectWebSocket(square, index), 1000);
+ };
+
+ square.ws.onerror = (error) => {
+ console.error(`WebSocket ${index + 1} error:`, error);
+ };
+
+ square.ws.onmessage = (event) => {
+ console.log(`WebSocket ${index + 1} message:`, event.data);
+ // 处理接收到的消息
+ try {
+ const message = JSON.parse(event.data);
+ const arr = JSON.parse(message.data);
+
+ if (Array.isArray(arr) && arr.length === 2) {
+ const [x, y] = arr;
+ console.log(`Creating dot at (${x}, ${y}) for square ${index}`);
+
+ const squareElement = document.querySelectorAll('.square')[index];
+ if (!squareElement) {
+ console.error('Square element not found');
+ return;
+ }
+
+ // 创建圆点元素
+ const dot = document.createElement('div');
+ dot.className = 'game-dot';
+ dot.style.left = `${x}px`;
+ dot.style.top = `${y}px`;
+ dot.style.zIndex = '10';
+
+ // 添加到游戏场景
+ squareElement.appendChild(dot);
+ console.log('Dot added successfully');
+ }
+ } catch (error) {
+ console.error('Error processing message:', error);
+ }
+ };
+ } catch (error) {
+ console.error(`WebSocket ${index + 1} init error:`, error);
+ }
+ }
+ }
+};
+
+createApp(App).mount('#app');
\ No newline at end of file
diff --git a/Client/web/index.html b/Client/web/index.html
new file mode 100644
index 0000000..2a58d15
--- /dev/null
+++ b/Client/web/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ 游戏方块容器
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Client/web/style.css b/Client/web/style.css
new file mode 100644
index 0000000..d855d00
--- /dev/null
+++ b/Client/web/style.css
@@ -0,0 +1,80 @@
+/* 重置默认边距 */
+body, html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ background-color: #f5f5f5;
+}
+
+/* 应用容器填满整个视口并居中 */
+.app-container {
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+/* 重置body样式 */
+body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+}
+
+/* 网格容器 - 固定2x2布局 */
+.grid-container {
+ display: grid;
+ grid-template-columns: 400px 400px;
+ grid-template-rows: 400px 400px;
+ gap: 30px;
+ padding: 40px;
+ background-color: #e0e0e0;
+ min-height: 100vh;
+ width: 100vw;
+ box-sizing: border-box;
+ margin: 0 auto;
+ place-content: center;
+}
+
+/* 正方形样式 */
+.square {
+ width: 400px;
+ height: 400px;
+ background-color: #ffffff;
+ background-image:
+ linear-gradient(to right, #ddd 1px, transparent 1px),
+ linear-gradient(to bottom, #ddd 1px, transparent 1px);
+ background-size: 20px 20px;
+ border: 5px solid #555;
+ border-radius: 15px;
+ position: relative;
+ box-shadow: 0 6px 12px rgba(0,0,0,0.15);
+}
+
+/* 连接状态圆点 */
+.connection-dot {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background-color: #ff4444; /* 默认断开状态-红色 */
+ transition: background-color 0.3s;
+}
+
+.connection-dot.connected {
+ background-color: #44ff44; /* 连接状态-绿色 */
+}
+
+/* 游戏动态圆点 */
+.game-dot {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ background-color: red;
+ border-radius: 50%;
+ transform: translate(-50%, -50%);
+ pointer-events: none;
+}
\ No newline at end of file
diff --git a/Server/Gateway/app/app.go b/Server/Gateway/app/app.go
index 1948e46..cef5995 100644
--- a/Server/Gateway/app/app.go
+++ b/Server/Gateway/app/app.go
@@ -9,7 +9,6 @@ import (
"fmt"
"gateway/config"
"gateway/grpc_server"
- "gateway/handler/ws_handler"
"github.com/gin-gonic/gin"
"github.com/judwhite/go-svc"
"runtime/debug"
@@ -52,10 +51,16 @@ func (p *Program) Start() error {
}()
discover.Listen()
- p.server = grpc_server.NewServer(config.Get().Grpc.Registry.TTL)
- p.server.Init(config.Get().Grpc.Registry.Address, config.Get().Grpc.Registry.Port)
-
- ws_handler.NewClient(123, nil)
+ p.server = grpc_server.NewServer(config.Get().Serve.Grpc.TTL)
+ p.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
+ go func() {
+ cfg := config.Get()
+ _ = p.wsServer.Run(
+ log.GetLogger().Named("gnet"),
+ fmt.Sprintf("tcp4://0.0.0.0:%v", cfg.Serve.Socket.Web.Port),
+ true, true, false, false, true, 8,
+ )
+ }()
return nil
}
diff --git a/Server/Gateway/app/websocket.go b/Server/Gateway/app/websocket.go
index 09dea50..c4b8988 100644
--- a/Server/Gateway/app/websocket.go
+++ b/Server/Gateway/app/websocket.go
@@ -25,7 +25,7 @@ func (p *Program) initWsServer(cfg *config.Config) error {
//)
p.wsServer = websocket.NewWSServer(
&ws_gateway.GatewayWsServer{},
- log.GetLogger(),
+ log.GetLogger().Named("ws_server"),
5*time.Second,
)
diff --git a/Server/Gateway/config/config.dev.yaml b/Server/Gateway/config/config.dev.yaml
index 8830d6e..637549d 100644
--- a/Server/Gateway/config/config.dev.yaml
+++ b/Server/Gateway/config/config.dev.yaml
@@ -8,12 +8,22 @@ log:
max_backups: 3
max_age: 7
-grpc:
- registry:
+db:
+ etcd:
+ address: [ "10.0.40.9:2379" ]
+
+serve:
+ grpc:
address: "10.0.40.199"
port: 8500
ttl: 20
-
-db:
- etcd:
- address: [ "10.0.40.9:2379" ]
\ No newline at end of file
+ socket:
+ web:
+ address: "0.0.0.0"
+ port: 8501
+ raw:
+ address: "0.0.0.0"
+ port: 8502
+ http:
+ address: "0.0.0.0"
+ port: 8503
diff --git a/Server/Gateway/config/config.go b/Server/Gateway/config/config.go
index e0214cc..94a8c32 100644
--- a/Server/Gateway/config/config.go
+++ b/Server/Gateway/config/config.go
@@ -1,10 +1,10 @@
package config
type Config struct {
- App AppConfig `yaml:"app"`
- Log LogConfig `yaml:"log"`
- Grpc GrpcConfig `yaml:"grpc"`
- DB DBConfig `yaml:"db"`
+ App *AppConfig `yaml:"app"`
+ Log *LogConfig `yaml:"log"`
+ DB *DBConfig `yaml:"db"`
+ Serve *ServeConfig `yaml:"serve"`
}
type AppConfig struct {
@@ -19,16 +19,25 @@ type LogConfig struct {
Level string `yaml:"level"`
}
-type GrpcConfig struct {
- Registry *struct {
- Address string `yaml:"address"`
- Port int `yaml:"port"`
- TTL int64 `yaml:"ttl"`
- } `yaml:"registry"`
-}
-
type DBConfig struct {
Etcd *struct {
Address []string `yaml:"address"`
} `yaml:"etcd"`
}
+
+type ServeConfig struct {
+ Grpc *struct {
+ AddressConfig
+ TTL int64 `yaml:"ttl"`
+ } `yaml:"grpc"`
+ Socket *struct {
+ Web *AddressConfig `yaml:"web"`
+ Raw *AddressConfig `yaml:"raw"`
+ } `yaml:"socket"`
+ Http *AddressConfig `yaml:"http"`
+}
+
+type AddressConfig struct {
+ Address string `yaml:"address"`
+ Port int `yaml:"port"`
+}
diff --git a/Server/Gateway/go.mod b/Server/Gateway/go.mod
index 19dcc34..1dbf73d 100644
--- a/Server/Gateway/go.mod
+++ b/Server/Gateway/go.mod
@@ -6,12 +6,9 @@ require (
common v0.0.0-00010101000000-000000000000
github.com/gin-contrib/cors v1.7.6
github.com/gin-gonic/gin v1.10.1
- github.com/gobwas/ws v1.4.0
- github.com/golang/protobuf v1.5.4
github.com/judwhite/go-svc v1.2.1
github.com/spf13/viper v1.20.1
- go.mongodb.org/mongo-driver v1.17.4
- golang.org/x/text v0.26.0
+ go.uber.org/zap v1.27.0
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.6
)
@@ -20,11 +17,9 @@ require (
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/bytedance/sonic v1.13.3 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
- github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/getsentry/sentry-go v0.34.0 // indirect
@@ -35,8 +30,10 @@ require (
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
+ github.com/gobwas/ws v1.4.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
@@ -48,7 +45,6 @@ require (
github.com/panjf2000/ants/v2 v2.11.3 // indirect
github.com/panjf2000/gnet/v2 v2.9.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
- github.com/redis/go-redis/v9 v9.10.0 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
@@ -62,12 +58,12 @@ require (
go.etcd.io/etcd/client/pkg/v3 v3.6.1 // indirect
go.etcd.io/etcd/client/v3 v3.6.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
- go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.18.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
+ golang.org/x/text v0.26.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
diff --git a/Server/Gateway/go.sum b/Server/Gateway/go.sum
index 7a9a8e0..2ad2ff0 100644
--- a/Server/Gateway/go.sum
+++ b/Server/Gateway/go.sum
@@ -1,9 +1,5 @@
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
-github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
-github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
-github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
@@ -11,8 +7,6 @@ github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
@@ -23,8 +17,6 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
@@ -112,8 +104,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
-github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
@@ -154,8 +144,6 @@ go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BS
go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc=
go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0=
go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY=
-go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
-go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
diff --git a/Server/Gateway/handler/ws_handler/client.go b/Server/Gateway/handler/ws_handler/client.go
index 66a4e00..a47db79 100644
--- a/Server/Gateway/handler/ws_handler/client.go
+++ b/Server/Gateway/handler/ws_handler/client.go
@@ -3,7 +3,9 @@ package ws_handler
import (
"common/log"
"common/net/socket"
+ "common/utils"
"context"
+ "fmt"
"go.uber.org/zap"
"runtime/debug"
"sync"
@@ -14,29 +16,90 @@ type Client struct {
sync.WaitGroup
conn socket.ISocketConn // Socket
mailChan chan Event // 邮箱队列
- logger *zap.SugaredLogger
- ctx context.Context
- cancel context.CancelFunc
- heartBeat time.Time
+ logger *zap.SugaredLogger // 日志
+ ctx context.Context // 上下文
+ cancel context.CancelFunc // 取消上下文
+ heartBeat time.Time // 最后一次心跳
UID int32
}
func NewClient(uid int32, conn socket.ISocketConn) *Client {
- client := &Client{}
- client.UID = uid
- client.conn = conn
- client.logger = log.GetLogger().Named("uid").With("uid", client.UID)
- client.logger.Errorf("错误日志 %v", 1)
-
- client.heartBeat = time.Now()
- client.mailChan = make(chan Event, 1024)
+ client := &Client{
+ UID: uid,
+ conn: conn,
+ logger: log.GetLogger().Named(fmt.Sprintf("uid:%v", uid)),
+ heartBeat: time.Now(),
+ mailChan: make(chan Event, 1024),
+ }
client.ctx, client.cancel = context.WithCancel(context.Background())
+ client.Add(1)
go client.Loop()
return client
}
-// CloseClient 关闭客户端
+func (c *Client) Loop() {
+ defer func() {
+ if err := recover(); err != nil {
+ c.logger.Errorf("Client Loop err: %v", err)
+ debug.PrintStack()
+ }
+ }()
+ defer c.onClose()
+ t := time.NewTicker(20 * time.Second)
+ defer t.Stop()
+ for {
+ select {
+ case <-c.ctx.Done():
+ return
+ case evt, ok := <-c.mailChan:
+ if ok {
+ c.handle(evt)
+ }
+ case <-t.C:
+ _ = c.conn.Ping()
+ if time.Now().Sub(c.heartBeat) > 120*time.Second {
+ return
+ }
+ }
+ }
+}
+
+func (c *Client) OnEvent(event Event) {
+ defer func() {
+ if err := recover(); err != nil {
+ c.logger.Warnf(fmt.Sprintf("send event chan error: %v", err))
+ }
+ }()
+ select {
+ case c.mailChan <- event:
+ default:
+ c.logger.Warnf("Client mailChan full")
+ }
+}
+
+func (c *Client) handle(event Event) {
+ switch e := event.(type) {
+ case *ClientEvent:
+ m, err := parseMsg(e.Msg)
+ if err != nil {
+ c.logger.Errorf("handle event json.Unmarshal err: %v", err)
+ c.cancel()
+ }
+ c.logger.Infof("收到客户端消息:%+v", *m)
+ switch m.Type {
+ case "init":
+ _ = c.conn.Write(wapMsg(&msg{
+ Type: "init",
+ Data: fmt.Sprintf("[%v,%v]", utils.RandInt(1, 100), utils.RandInt(1, 100)),
+ }))
+ }
+ case *PongEvent:
+ c.heartBeat = time.Now()
+ }
+}
+
+// CloseClient 关闭客户端(同步,会等待onClose执行完成)
func (c *Client) CloseClient() {
if c.cancel != nil {
c.cancel()
@@ -56,34 +119,3 @@ func (c *Client) onClose() {
UserMgr.Delete(c.UID)
c.Done()
}
-
-func (c *Client) Loop() {
- defer func() {
- if err := recover(); err != nil {
- c.logger.Errorf("Client Loop err: %v", err)
- debug.PrintStack()
- }
- }()
- defer c.onClose()
- c.Add(1)
- //心跳检测
- hearBeatTicker := time.NewTicker(3000 * time.Millisecond)
- for {
- select {
- case <-c.ctx.Done():
- return
- case _, _ = <-c.mailChan:
-
- case <-hearBeatTicker.C:
- // 心跳超时直接关掉连接
- if c.checkHeartBeatTimeout() {
- return
- }
- }
- }
-}
-
-func (c *Client) checkHeartBeatTimeout() bool {
- sub := time.Now().Sub(c.heartBeat)
- return sub > 60*time.Second
-}
diff --git a/Server/Gateway/handler/ws_handler/event.go b/Server/Gateway/handler/ws_handler/event.go
index 9fa9ae4..7a1ef51 100644
--- a/Server/Gateway/handler/ws_handler/event.go
+++ b/Server/Gateway/handler/ws_handler/event.go
@@ -1,18 +1,13 @@
package ws_handler
-import (
- "google.golang.org/protobuf/proto"
-)
-
type Event interface {
}
-// ClientEvent 客户端发过来的Event
type ClientEvent struct {
Event
- Msg proto.Message
+ Msg []byte
}
-type RemoveConnectionEvent struct {
+type PongEvent struct {
Event
}
diff --git a/Server/Gateway/handler/ws_handler/temp.go b/Server/Gateway/handler/ws_handler/temp.go
new file mode 100644
index 0000000..7a2cdda
--- /dev/null
+++ b/Server/Gateway/handler/ws_handler/temp.go
@@ -0,0 +1,21 @@
+package ws_handler
+
+import "encoding/json"
+
+type msg struct {
+ Type string `json:"type"`
+ Data string `json:"data"`
+}
+
+func parseMsg(data []byte) (*msg, error) {
+ m := &msg{}
+ if err := json.Unmarshal(data, m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func wapMsg(m *msg) []byte {
+ data, _ := json.Marshal(m)
+ return data
+}
diff --git a/Server/Gateway/net/ws_gateway/server.go b/Server/Gateway/net/ws_gateway/server.go
index 871adaa..f3b475b 100644
--- a/Server/Gateway/net/ws_gateway/server.go
+++ b/Server/Gateway/net/ws_gateway/server.go
@@ -1,27 +1,59 @@
package ws_gateway
import (
+ "common/log"
"common/net/socket"
+ "fmt"
+ "gateway/handler/ws_handler"
+ "go.uber.org/zap"
+ "strconv"
"time"
)
type GatewayWsServer struct {
+ logger *zap.SugaredLogger
}
-func (g *GatewayWsServer) OnOpen(_ socket.ISocketConn) ([]byte, socket.Action) {
+func (g *GatewayWsServer) OnOpen(conn socket.ISocketConn) ([]byte, socket.Action) {
+ g.logger = log.GetLogger().Named(fmt.Sprintf("addr:%v", conn.RemoteAddr()))
return nil, socket.None
}
func (g *GatewayWsServer) OnHandShake(conn socket.ISocketConn) {
- //query := conn.GetParam("query")
+ token, ok := conn.GetParam("token").(string)
+ if !ok || len(token) == 0 {
+ g.logger.Warnf("token is not string")
+ _ = conn.Close()
+ return
+ }
+ t, err := strconv.Atoi(token)
+ if err != nil {
+ _ = conn.Close()
+ }
+ client := ws_handler.NewClient(int32(t), conn)
+ ws_handler.UserMgr.Add(int32(t), client)
+ conn.SetParam("client", client)
}
func (g *GatewayWsServer) OnMessage(conn socket.ISocketConn, bytes []byte) socket.Action {
+ client, ok := conn.GetParam("client").(*ws_handler.Client)
+ if !ok || client.UID == 0 {
+ return socket.Close
+ }
+ client.OnEvent(&ws_handler.ClientEvent{Msg: bytes})
return socket.None
}
-func (g *GatewayWsServer) OnClose(conn socket.ISocketConn, _ error) socket.Action {
- return socket.None
+func (g *GatewayWsServer) OnPong(conn socket.ISocketConn) {
+ client, ok := conn.GetParam("client").(*ws_handler.Client)
+ if !ok || client.UID == 0 {
+ return
+ }
+ client.OnEvent(&ws_handler.PongEvent{})
+}
+
+func (g *GatewayWsServer) OnClose(_ socket.ISocketConn, _ error) socket.Action {
+ return socket.Close
}
func (g *GatewayWsServer) OnTick() (time.Duration, socket.Action) {
diff --git a/Server/common/log/log_zap.go b/Server/common/log/log_zap.go
index 19d85a5..c9d3278 100644
--- a/Server/common/log/log_zap.go
+++ b/Server/common/log/log_zap.go
@@ -56,7 +56,7 @@ func Init(debug bool, maxSize, maxBackups, maxAge int, level string) {
logger = logger.WithOptions(
zap.AddCaller(),
zap.AddCallerSkip(1),
- zap.AddStacktrace(zapcore.WarnLevel),
+ zap.AddStacktrace(zapcore.ErrorLevel),
)
}
SetLogger(logger.Sugar())
diff --git a/Server/common/net/socket/server.go b/Server/common/net/socket/server.go
index 1d8e830..2b799f4 100644
--- a/Server/common/net/socket/server.go
+++ b/Server/common/net/socket/server.go
@@ -15,19 +15,33 @@ const (
Shutdown
)
+type OpCode byte
+
+const (
+ OpContinuation OpCode = 0x0
+ OpText OpCode = 0x1
+ OpBinary OpCode = 0x2
+ OpClose OpCode = 0x8
+ OpPing OpCode = 0x9
+ OpPong OpCode = 0xa
+)
+
// ISocketServer 由应用层实现
type ISocketServer interface {
OnOpen(ISocketConn) ([]byte, Action) // 开启连接
OnHandShake(ISocketConn) // 开始握手
OnMessage(ISocketConn, []byte) Action // 收到消息
- OnClose(ISocketConn, error) Action // 关闭连接
+ OnPong(ISocketConn)
+ OnClose(ISocketConn, error) Action // 关闭连接
OnTick() (time.Duration, Action)
}
// ISocketConn 由网络层实现
type ISocketConn interface {
- GetParam(key string) string
- SetParam(key string, values string)
+ GetParam(key string) interface{}
+ SetParam(key string, values interface{})
+ RemoteAddr() string
+ Ping() error // 需要隔一段时间调用一下,建议20s
Write(data []byte) error
Close() error
}
diff --git a/Server/common/net/socket/websocket/websocket.go b/Server/common/net/socket/websocket/websocket.go
index fae657e..f402b0d 100644
--- a/Server/common/net/socket/websocket/websocket.go
+++ b/Server/common/net/socket/websocket/websocket.go
@@ -66,7 +66,8 @@ func (s *WSServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
curHeader: nil,
cachedBuf: bytes.Buffer{},
},
- param: make(map[string]string),
+ param: make(map[string]interface{}),
+ remoteAddr: c.RemoteAddr().String(),
}
c.SetContext(ws)
s.unUpgradeConn.Store(c.RemoteAddr().String(), ws)
@@ -78,10 +79,10 @@ func (s *WSServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
// The parameter err is the last known connection error.
func (s *WSServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
s.unUpgradeConn.Delete(c.RemoteAddr().String())
- tmp := c.Context()
- ws, ok := tmp.(*WSConn)
+ ws, ok := c.Context().(*WSConn)
if ok {
- s.logger.Warnf("connection close")
+ ws.isClose = true
+ ws.logger.Warnf("connection close: %v --------------------------------------------------", err)
return gnet.Action(s.i.OnClose(ws, err))
}
return
@@ -91,18 +92,14 @@ func (s *WSServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
func (s *WSServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
tmp := c.Context()
if tmp == nil {
- if s.logger != nil {
- s.logger.Errorf("OnTraffic context nil: %v", c)
- }
+ s.logger.Errorf("OnTraffic context nil: %v", c)
action = gnet.Close
return
}
ws, ok := tmp.(*WSConn)
if !ok {
- if s.logger != nil {
- s.logger.Errorf("OnTraffic convert ws error: %v", tmp)
- }
+ ws.logger.Errorf("OnTraffic convert ws error: %v", tmp)
action = gnet.Close
return
}
@@ -121,9 +118,7 @@ func (s *WSServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
if data != nil {
err := ws.Conn.AsyncWrite(data, nil)
if err != nil {
- if ws.logger != nil {
- ws.logger.Errorf("update ws write upgrade protocol error", err)
- }
+ ws.logger.Errorf("update ws write upgrade protocol error", err)
action = gnet.Close
}
}
@@ -131,14 +126,22 @@ func (s *WSServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
} else {
msg, err := ws.readWsMessages()
if err != nil {
- if ws.logger != nil {
- ws.logger.Errorf("read ws messages errors", err)
- }
+ ws.logger.Errorf("read ws messages errors", err)
return gnet.Close
}
if msg != nil {
for _, m := range msg {
+ if socket.OpCode(m.OpCode) == socket.OpPong {
+ s.i.OnPong(ws)
+ continue
+ }
+ if socket.OpCode(m.OpCode) == socket.OpClose {
+ return gnet.Close
+ }
+ if socket.OpCode(m.OpCode) == socket.OpPing {
+ continue
+ }
a := s.i.OnMessage(ws, m.Payload)
if gnet.Action(a) != gnet.None {
action = gnet.Action(a)
@@ -182,10 +185,7 @@ func (s *WSServer) OnTick() (delay time.Duration, action gnet.Action) {
continue
}
if err := v.Close(); err != nil {
- if s.logger != nil {
- s.logger.Errorf("upgrade ws time out close socket error: %v", err)
- continue
- }
+ v.logger.Errorf("upgrade ws time out close socket error: %v", err)
}
}
d, a := s.i.OnTick()
diff --git a/Server/common/net/socket/websocket/wsconn.go b/Server/common/net/socket/websocket/wsconn.go
index f54c265..adefbc2 100644
--- a/Server/common/net/socket/websocket/wsconn.go
+++ b/Server/common/net/socket/websocket/wsconn.go
@@ -15,12 +15,13 @@ import (
// WSConn 实现ISocketConn接口
type WSConn struct {
gnet.Conn
- buf bytes.Buffer
- logger logging.Logger
- isUpgrade bool
- isClose bool
- param map[string]string
- openTime int64
+ buf bytes.Buffer
+ logger logging.Logger
+ isUpgrade bool
+ isClose bool
+ param map[string]interface{}
+ openTime int64
+ remoteAddr string
wsMessageBuf
}
@@ -169,19 +170,24 @@ func (w *WSConn) OnRequest(u []byte) error {
return nil
}
-func (w *WSConn) GetParam(key string) string {
+func (w *WSConn) GetParam(key string) interface{} {
return w.param[key]
}
-func (w *WSConn) SetParam(key string, values string) {
+func (w *WSConn) SetParam(key string, values interface{}) {
w.param[key] = values
}
+func (w *WSConn) RemoteAddr() string {
+ return w.remoteAddr
+}
+
func (w *WSConn) Write(data []byte) error {
- if w.isClose {
- return errors.New("connection has close")
- }
- return w.write(data, ws.OpBinary)
+ return w.write(data, ws.OpText)
+}
+
+func (w *WSConn) Ping() (err error) {
+ return w.write(make([]byte, 0), ws.OpPing)
}
func (w *WSConn) Close() (err error) {
@@ -192,74 +198,12 @@ func (w *WSConn) Close() (err error) {
}
func (w *WSConn) write(data []byte, opCode ws.OpCode) error {
+ if w.isClose {
+ return errors.New("connection has close")
+ }
buf := bytes.Buffer{}
- err := wsutil.WriteServerMessage(&buf, opCode, data)
- if err != nil {
+ if err := wsutil.WriteServerMessage(&buf, opCode, data); err != nil {
return err
}
return w.Conn.AsyncWrite(buf.Bytes(), nil)
}
-
-//func (w *WSConn) Pong(data []byte) (err error) {
-// buf := bytes.Buffer{}
-// if data == nil {
-// err = wsutil.WriteServerMessage(&buf, ws.OpPong, emptyPayload)
-// } else {
-// err = wsutil.WriteServerMessage(&buf, ws.OpPong, data)
-// }
-// if w.isClose {
-// return errors.New("connection has close")
-// }
-// if err != nil {
-// return
-// }
-// return w.Conn.AsyncWrite(buf.Bytes(), nil)
-//}
-
-//func (w *WSConn) Ping(data []byte) (err error) {
-// buf := bytes.Buffer{}
-// if data == nil {
-// err = wsutil.WriteServerMessage(&buf, ws.OpPing, emptyPayload)
-// } else {
-// err = wsutil.WriteServerMessage(&buf, ws.OpPing, data)
-// }
-// if w.isClose {
-// return errors.New("connection has close")
-// }
-// if err != nil {
-// return err
-// }
-//
-// return w.Conn.AsyncWrite(buf.Bytes(), nil)
-//}
-
-//func (w *WSConn) GetProperty(key string) (interface{}, error) {
-// if w.context[key] == nil {
-// return nil, errors.New("not found this key")
-// }
-// return w.context[key], nil
-//}
-//
-//func (w *WSConn) SetProperty(key string, ctx interface{}) {
-// w.context[key] = ctx
-//}
-//
-//func (w *WSConn) RemoveProperty(key string) {
-// delete(w.context, key)
-//}
-//
-//func (w *WSConn) GetConnID() uint64 {
-// return w.connID
-//}
-//
-//func (w *WSConn) Clear() {
-// w.context = make(map[string]interface{})
-//}
-//
-//func (w *WSConn) GetUrlParam() map[string][]string {
-// return w.urlParma
-//}
-//
-//func (w *WSConn) SetUrlParam(key string, values []string) {
-// w.urlParma[key] = values
-//}
diff --git a/Server/common/proto/cs/define.proto b/Server/common/proto/cs/define.proto
new file mode 100644
index 0000000..a76efc0
--- /dev/null
+++ b/Server/common/proto/cs/define.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+option go_package = "common/proto/gen/cs";
+import "common.proto";
+
+enum MessageID {
+ MESSAGE_ID_INVALID = 0;
+
+ // 移动指令
+ MESSAGE_TYPE_PLAYER_MOVE = 3;
+
+ // 聊天消息
+ MESSAGE_TYPE_CHAT_MESSAGE = 4;
+
+ // 心跳包
+ MESSAGE_TYPE_HEARTBEAT = 5;
+}
+
+message Message {
+ MessageID id = 1;
+ bytes payload = 2;
+}
\ No newline at end of file
diff --git a/Server/common/utils/number.go b/Server/common/utils/number.go
new file mode 100644
index 0000000..1fd4f07
--- /dev/null
+++ b/Server/common/utils/number.go
@@ -0,0 +1,13 @@
+package utils
+
+import (
+ "math/rand"
+)
+
+// RandInt 生成 [min, max] 范围内的随机整数
+func RandInt(min, max int) int {
+ if min > max {
+ min, max = max, min
+ }
+ return rand.Intn(max-min+1) + min
+}