feat(socket): 实现 WebSocket 代理功能

- 新增 WebSocket 中间件,支持连接到指定端口的 TCP 服务器
- 在 ServerEvent 中添加错误日志输出
- 优化 ClientData 解析逻辑,增加类型断言
- 更新 index.html,添加 socket 代理配置
This commit is contained in:
2025-07-10 01:01:43 +08:00
parent c76c2f4139
commit cd2a5db9d2
5 changed files with 111 additions and 6 deletions

View File

@@ -22,6 +22,7 @@ func (s *Server) Boot() error {
return err return err
} }
// err := gnet.Run(s, s.network+"://"+s.addr, gnet.WithMulticore(s.multicore)) // err := gnet.Run(s, s.network+"://"+s.addr, gnet.WithMulticore(s.multicore))
glog.Debug(context.Background(), "server exits with error: %v", err)
// logging.Infof("server exits with error: %v", err) // logging.Infof("server exits with error: %v", err)
return nil return nil
} }
@@ -36,7 +37,11 @@ func (s *Server) Stop() error {
func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) { func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) {
atomic.AddInt64(&s.connected, -1) atomic.AddInt64(&s.connected, -1)
//logging.Infof("conn[%v] disconnected", c.RemoteAddr().String()) //logging.Infof("conn[%v] disconnected", c.RemoteAddr().String())
v := c.Context().(*entity.ClientData) v, ok := c.Context().(*entity.ClientData)
if !ok {
return
}
t := v.GetPlayer() t := v.GetPlayer()
if t != nil { if t != nil {
glog.Debug(context.Background(), t.UserID, "断开连接") glog.Debug(context.Background(), t.UserID, "断开连接")

View File

@@ -7,6 +7,7 @@ import (
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/gconv"
"github.com/lxzan/gws" "github.com/lxzan/gws"
) )
@@ -41,9 +42,13 @@ func init() {
if config.Config.Middleware.Log.Enable { if config.Config.Middleware.Log.Enable {
g.Server().BindMiddleware("/admin/*", BaseLog) g.Server().BindMiddleware("/admin/*", BaseLog)
} }
g.Server().BindHandler("/ws", func(r *ghttp.Request) { g.Server().BindHandler("/ws/*", func(r *ghttp.Request) {
urls := r.URL.Query().Get("port")
fmt.Println(urls)
tt := new(Handler)
upgrader := gws.NewUpgrader(new(Handler), &gws.ServerOption{ tt.port = gconv.Int(urls)
upgrader := gws.NewUpgrader(tt, &gws.ServerOption{
//CompressEnabled: true, //CompressEnabled: true,
// 在querystring里面传入用户名 // 在querystring里面传入用户名

View File

@@ -1,9 +1,16 @@
package middleware package middleware
import ( import (
"fmt" "bufio"
"context"
"encoding/binary"
"io"
"log"
"net"
"time" "time"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/util/gconv"
"github.com/lxzan/gws" "github.com/lxzan/gws"
) )
@@ -11,10 +18,51 @@ const PingInterval = 10 * time.Second
type Handler struct { type Handler struct {
gws.BuiltinEventHandler gws.BuiltinEventHandler
port int
target net.Conn
} }
func (c *Handler) OnOpen(socket *gws.Conn) { func (c *Handler) OnOpen(socket *gws.Conn) {
target, err := net.Dial("tcp", "127.0.0.1:"+gconv.String(c.port))
if err != nil {
glog.Debug(context.Background(), "连接失败")
}
c.target = target
//errChan := make(chan error, 2)
go func(conn net.Conn, socket *gws.Conn) {
reader := bufio.NewReader(conn)
LOOP:
for {
// select {
// default:
packlen, err := reader.Peek(4)
if err != nil {
break LOOP
}
length := int32(binary.BigEndian.Uint32(packlen))
data := make([]byte, length)
io.ReadFull(reader, data)
//pack_Ver := data[4] //因为包体已经解析所以这里直接取0
// var pack = make([]byte, length)
socket.WriteMessage(gws.OpcodeBinary, data)
//t.event.RecvHandler(pack)
// client.OnReceiveBase(client, pack, length)
}
}(c.target, socket)
//err = <-errChan
if err != io.EOF {
log.Println("proxy error:", err)
}
} }
func (c *Handler) OnPing(socket *gws.Conn, payload []byte) { func (c *Handler) OnPing(socket *gws.Conn, payload []byte) {
@@ -25,7 +73,20 @@ func (c *Handler) OnPing(socket *gws.Conn, payload []byte) {
func (c *Handler) OnPong(socket *gws.Conn, payload []byte) {} func (c *Handler) OnPong(socket *gws.Conn, payload []byte) {}
func (c *Handler) OnMessage(socket *gws.Conn, gwsmessage *gws.Message) { func (c *Handler) OnMessage(socket *gws.Conn, gwsmessage *gws.Message) {
fmt.Println(gwsmessage.Bytes()) if c.target != nil {
c.target.Write(gwsmessage.Bytes())
}
//fmt.Println(gwsmessage.Bytes())
}
func (c *Handler) OnClose(socket *gws.Conn, err error) {
glog.Debug(context.Background(), "断开连接")
if c.target != nil {
c.target.Close()
}
} }

View File

@@ -23,19 +23,52 @@
flex-shrink: 0; /* 防止播放器被压缩 */ flex-shrink: 0; /* 防止播放器被压缩 */
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
:root {
--logo-display: block; /* 默认值,可以是 inline, flex, none 等 */
--logo-width: 150px; /* Logo 宽度 */
--logo-height: auto; /* Logo 高度,保持比例 */
}
</style> </style>
</head> </head>
<body> <body>
<div id="container"></div> <div id="container" style="--logo-display: none; --splash-screen-background:rgb(97,171,245)"></div>
<script src="//unpkg.com/@ruffle-rs/ruffle"></script> <script src="//unpkg.com/@ruffle-rs/ruffle"></script>
<script> <script>
function generateAllPortsProxy(host, baseUrl = "ws://localhost:8080/ws/?port=") {
// 生成1-65535范围内的所有端口配置
const socketProxy = [];
for (let port = 1; port <= 65535; port++) {
socketProxy.push({
host: host,
port: port,
proxyUrl: `${baseUrl}${port}`
});
}
return socketProxy;
}
window.addEventListener('load', async () => { window.addEventListener('load', async () => {
const ruffle = window.RufflePlayer.newest(); const ruffle = window.RufflePlayer.newest();
const player = ruffle.createPlayer(); const player = ruffle.createPlayer();
const container = document.getElementById('container'); const container = document.getElementById('container');
container.appendChild(player); container.appendChild(player);
window.RufflePlayer.config = { window.RufflePlayer.config = {
"autoplay": "on",
"contextMenu": "off",
"numFrames":6,
// "frameRate": 60,
socketProxy: [
{
host: "127.0.0.1", // The address of the server that Flash tries to connect to
port: 12345, // The port that Flash tries to connect to
proxyUrl: "ws://localhost:8080/ws/0", // The actual proxy that Ruffle will connect to, instead of the above server
}
],
fontSources: ["fonts/simsun.ttf","fonts/Tahoma.ttf"], // load up fonts here fontSources: ["fonts/simsun.ttf","fonts/Tahoma.ttf"], // load up fonts here
defaultFonts: { defaultFonts: {
sans: ["simsun"], // then replace them here. sans: ["simsun"], // then replace them here.
@@ -46,6 +79,7 @@
// japaneseMincho: ["font"], // japaneseMincho: ["font"],
} }
} }
window.RufflePlayer.config.socketProxy = generateAllPortsProxy("127.0.0.1");
player.load('Client.swf'); player.load('Client.swf');
}); });
</script> </script>

Binary file not shown.