优化连接

This commit is contained in:
kercylan98 2023-05-06 15:53:31 +08:00
parent dae2982090
commit 41b0417338
18 changed files with 21 additions and 305 deletions

View File

@ -1 +0,0 @@
简单游戏实现demo

View File

@ -1,23 +0,0 @@
package game
import (
"minotaur/game"
"minotaur/game/builtin"
"minotaur/server"
)
var (
Server *server.Server
Game *app
)
func init() {
Server = server.New(server.NetworkWebsocket)
Game = &app{
World: builtin.NewWorld[int64, *Player](0),
}
}
type app struct {
game.World[int64, *Player]
}

View File

@ -1,43 +0,0 @@
package game
import (
"log"
"minotaur/game"
"minotaur/game/builtin"
"minotaur/server"
"time"
)
func NewPlayer(id int64, conn *server.Conn) *Player {
player := &Player{
Player: builtin.NewPlayer[int64](id, conn),
}
gameplay := builtin.NewGameplay()
gameplayOver := builtin.NewGameplayOver()
gameplayTime := builtin.NewGameplayTime(gameplay, gameplayOver)
player.GameplayTime = gameplayTime
return player
}
type Player struct {
*builtin.Player[int64]
game.GameplayTime
}
func (slf *Player) Start() {
_ = slf.GameStart(func() error {
log.Println("game start, init map...")
return nil
})
}
func (slf *Player) onGameplayStart(t time.Time) {
slf.SetEndTime(t.Add(60 * time.Second))
log.Println("the game will end in 60 seconds")
}
func (slf *Player) onGameplayOver() {
log.Println("game over")
}

View File

@ -1,40 +0,0 @@
package game
import (
"minotaur/game"
"minotaur/server"
"minotaur/utils/sole"
)
func init() {
Server.RegConnectionOpenedEvent(onConnectionOpened)
Game.RegPlayerLeaveWorldEvent(onConnectionClosed)
Server.RegConnectionReceivePacketEvent(onConnectionReceivePacket)
}
func onConnectionReceivePacket(srv *server.Server, conn *server.Conn, packet []byte) {
player := Game.World.GetPlayerWithConnID(conn.GetID())
if player == nil {
return
}
player.RegGameplayStartEvent(player.onGameplayStart)
player.RegGameplayOverEvent(player.onGameplayOver)
switch string(packet) {
case "start":
player.Start()
}
}
func onConnectionClosed(world game.World[int64, *Player], player *Player) {
Game.Leave(player.GetID())
player.Close()
}
func onConnectionOpened(srv *server.Server, conn *server.Conn) {
player := NewPlayer(sole.GetSync(), conn)
if err := Game.World.Join(player); err != nil {
panic(err)
}
}

View File

@ -1,9 +0,0 @@
package main
import "minotaur/game/builtin/examples/game/game"
func main() {
if err := game.Server.Run(":9999"); err != nil {
panic(err)
}
}

View File

@ -1,49 +0,0 @@
package main
import (
"log"
"minotaur/game"
"minotaur/game/builtin"
"sync"
"time"
)
func NewGame() *Game {
gameplay := builtin.NewGameplay()
gameplayOver := builtin.NewGameplayOver()
return &Game{
GameplayTime: builtin.NewGameplayTime(gameplay, gameplayOver),
}
}
type Game struct {
game.GameplayTime
wait sync.WaitGroup
}
func (slf *Game) init() error {
slf.wait.Add(1)
return nil
}
func (slf *Game) onGameStart(startTime time.Time) {
log.Println("游戏开始")
slf.SetEndTime(startTime.Add(3 * time.Second))
}
func (slf *Game) onGameOver() {
log.Println("游戏结束")
slf.wait.Done()
}
func main() {
g := NewGame()
g.RegGameplayStartEvent(g.onGameStart)
g.RegGameplayOverEvent(g.onGameOver)
if err := g.GameStart(g.init); err != nil {
panic(err)
}
g.wait.Wait()
}

View File

@ -1,40 +0,0 @@
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "server.natappfree.cc:37775")
if err != nil {
panic(err)
return
}
defer conn.Close() // 关闭TCP连接
inputReader := bufio.NewReader(os.Stdin)
go func() {
for {
buf := [512]byte{}
n, err := conn.Read(buf[:])
if err != nil {
continue
}
fmt.Println(string(buf[:n]))
}
}()
for {
input, _ := inputReader.ReadString('\n') // 读取用户输入
inputInfo := strings.Trim(input, "\r\n")
if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
return
}
_, err := conn.Write([]byte(inputInfo)) // 发送数据
if err != nil {
return
}
}
}

View File

@ -1,29 +0,0 @@
package main
import (
"fmt"
"go.uber.org/zap"
"minotaur/server"
"minotaur/utils/log"
)
func main() {
srv := server.New(server.NetworkTCP)
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
srv.GetConnections().RangeSkip(func(id string, c *server.Conn) bool {
if id == conn.GetID() {
return false
}
if err := c.Write([]byte(fmt.Sprintf("[%s]: %s", conn.GetID(), string(packet)))); err != nil {
log.Debug("Message", zap.Error(err))
}
return true
})
})
if err := srv.Run(":8888"); err != nil {
panic(err)
}
}

View File

@ -19,10 +19,6 @@ func (slf *Player[ID]) GetID() ID {
return slf.id
}
func (slf *Player[ID]) GetConnID() string {
return slf.conn.GetID()
}
// Send 向该玩家发送数据
func (slf *Player[ID]) Send(packet []byte) error {
return slf.conn.Write(packet)

View File

@ -9,9 +9,8 @@ import (
func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64) *Room[PlayerID, Player] {
return &Room[PlayerID, Player]{
guid: guid,
playersConn: synchronization.NewMap[string, Player](),
players: synchronization.NewMap[PlayerID, Player](),
guid: guid,
players: synchronization.NewMap[PlayerID, Player](),
}
}
@ -20,7 +19,6 @@ type Room[PlayerID comparable, Player game.Player[PlayerID]] struct {
owner PlayerID
noMaster bool
playerLimit int
playersConn *synchronization.Map[string, Player]
players *synchronization.Map[PlayerID, Player]
kickCheckHandle func(id, target PlayerID) error
@ -37,10 +35,6 @@ func (slf *Room[PlayerID, Player]) GetPlayerLimit() int {
return slf.playerLimit
}
func (slf *Room[PlayerID, Player]) GetPlayerWithConnID(id string) Player {
return slf.playersConn.Get(id)
}
func (slf *Room[PlayerID, Player]) GetPlayer(id PlayerID) Player {
return slf.players.Get(id)
}
@ -68,9 +62,8 @@ func (slf *Room[PlayerID, Player]) Join(player Player) error {
if slf.players.Size() >= slf.playerLimit && slf.playerLimit > 0 {
return ErrWorldPlayerLimit
}
log.Debug("Room.Join", zap.Any("guid", slf.GetGuid()), zap.Any("player", player.GetID()), zap.String("conn", player.GetConnID()))
log.Debug("Room.Join", zap.Any("guid", slf.GetGuid()), zap.Any("player", player.GetID()))
slf.players.Set(player.GetID(), player)
slf.playersConn.Set(player.GetConnID(), player)
if slf.players.Size() == 1 && !slf.noMaster {
slf.owner = player.GetID()
}
@ -83,10 +76,9 @@ func (slf *Room[PlayerID, Player]) Leave(id PlayerID) {
if !exist {
return
}
log.Debug("Room.Leave", zap.Any("guid", slf.GetGuid()), zap.Any("player", player.GetID()), zap.String("conn", player.GetConnID()))
log.Debug("Room.Leave", zap.Any("guid", slf.GetGuid()), zap.Any("player", player.GetID()))
slf.OnPlayerLeaveRoomEvent(player)
slf.players.Delete(player.GetID())
slf.playersConn.Delete(player.GetConnID())
}
func (slf *Room[PlayerID, Player]) KickOut(id, target PlayerID, reason string) error {

View File

@ -12,7 +12,6 @@ import (
func NewWorld[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...WorldOption[PlayerID, Player]) *World[PlayerID, Player] {
world := &World[PlayerID, Player]{
guid: guid,
playersConn: synchronization.NewMap[string, Player](),
players: synchronization.NewMap[PlayerID, Player](),
playerActors: synchronization.NewMap[PlayerID, *synchronization.Map[int64, game.Actor]](),
owners: synchronization.NewMap[int64, PlayerID](),
@ -29,7 +28,6 @@ type World[PlayerID comparable, Player game.Player[PlayerID]] struct {
guid int64
actorGuid atomic.Int64
playerLimit int
playersConn *synchronization.Map[string, Player]
players *synchronization.Map[PlayerID, Player]
playerActors *synchronization.Map[PlayerID, *synchronization.Map[int64, game.Actor]]
owners *synchronization.Map[int64, PlayerID]
@ -54,10 +52,6 @@ func (slf *World[PlayerID, Player]) GetPlayerLimit() int {
return slf.playerLimit
}
func (slf *World[PlayerID, Player]) GetPlayerWithConnID(id string) Player {
return slf.playersConn.Get(id)
}
func (slf *World[PlayerID, Player]) GetPlayer(id PlayerID) Player {
return slf.players.Get(id)
}
@ -108,13 +102,12 @@ func (slf *World[PlayerID, Player]) Join(player Player) error {
if slf.players.Size() >= slf.playerLimit && slf.playerLimit > 0 {
return ErrWorldPlayerLimit
}
log.Debug("World.Join", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID()), zap.String("conn", player.GetConnID()))
log.Debug("World.Join", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID()))
slf.players.Set(player.GetID(), player)
if actors := slf.playerActors.Get(player.GetID()); actors == nil {
actors = synchronization.NewMap[int64, game.Actor]()
slf.playerActors.Set(player.GetID(), actors)
}
slf.playersConn.Set(player.GetConnID(), player)
slf.OnPlayerJoinWorldEvent(player)
return nil
}
@ -124,7 +117,7 @@ func (slf *World[PlayerID, Player]) Leave(id PlayerID) {
if !exist {
return
}
log.Debug("World.Leave", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID()), zap.String("conn", player.GetConnID()))
log.Debug("World.Leave", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID()))
slf.OnPlayerLeaveWorldEvent(player)
slf.playerActors.Get(player.GetID()).Range(func(guid int64, actor game.Actor) {
slf.OnActorAnnihilationEvent(actor)
@ -132,7 +125,6 @@ func (slf *World[PlayerID, Player]) Leave(id PlayerID) {
})
slf.playerActors.Delete(player.GetID())
slf.players.Delete(player.GetID())
slf.playersConn.Delete(player.GetConnID())
}
func (slf *World[PlayerID, Player]) AddActor(actor game.Actor) {
@ -186,7 +178,6 @@ func (slf *World[PlayerID, Player]) Reset() {
slf.owners.Clear()
slf.actors.Clear()
slf.actorGuid.Store(0)
slf.playersConn.Clear()
slf.OnWorldResetEvent()
}

View File

@ -4,8 +4,6 @@ package game
type Player[ID comparable] interface {
// GetID 用户玩家ID
GetID() ID
// GetConnID 获取连接ID
GetConnID() string
// Send 发送数据包
Send(packet []byte) error
// Close 关闭玩家并且释放其资源

View File

@ -8,8 +8,6 @@ type Room[PlayerID comparable, P Player[PlayerID]] interface {
GetGuid() int64
// GetPlayerLimit 获取玩家人数上限
GetPlayerLimit() int
// GetPlayerWithConnID 根据连接ID获取玩家
GetPlayerWithConnID(id string) P
// GetPlayer 根据玩家id获取玩家
GetPlayer(id PlayerID) P
// GetPlayers 获取房间中的所有玩家

View File

@ -8,8 +8,6 @@ type World[PlayerID comparable, P Player[PlayerID]] interface {
GetGuid() int64
// GetPlayerLimit 获取玩家人数上限
GetPlayerLimit() int
// GetPlayerWithConnID 根据连接ID获取玩家
GetPlayerWithConnID(id string) P
// GetPlayer 根据玩家id获取玩家
GetPlayer(id PlayerID) P
// GetPlayers 获取世界中的所有玩家

View File

@ -30,9 +30,9 @@ func newGNetConn(conn gnet.Conn) *Conn {
}
// newKcpConn 创建一个处理WebSocket的连接
func newWebsocketConn(ws *websocket.Conn) *Conn {
func newWebsocketConn(ws *websocket.Conn, ip string) *Conn {
return &Conn{
ip: ws.RemoteAddr().String(),
ip: ip,
ws: ws,
write: func(data []byte) error {
return ws.WriteMessage(websocket.BinaryMessage, data)

View File

@ -57,7 +57,6 @@ func (slf *event) RegConnectionClosedEvent(handle ConnectionClosedEventHandle) {
func (slf *event) OnConnectionClosedEvent(conn *Conn) {
log.Debug("Server", zap.String("ConnectionClosed", conn.GetID()))
slf.Server.connections.Delete(conn.ip)
for _, handle := range slf.connectionClosedEventHandles {
handle(slf.Server, conn)
}
@ -74,7 +73,6 @@ func (slf *event) RegConnectionOpenedEvent(handle ConnectionOpenedEventHandle) {
func (slf *event) OnConnectionOpenedEvent(conn *Conn) {
log.Debug("Server", zap.String("ConnectionOpened", conn.GetID()))
slf.Server.connections.Set(conn.ip, conn)
for _, handle := range slf.connectionOpenedEventHandles {
handle(slf.Server, conn)
}

View File

@ -2,36 +2,29 @@ package server
import (
"github.com/panjf2000/gnet"
"minotaur/utils/synchronization"
"time"
)
type gNet struct {
*Server
connections *synchronization.Map[string, *Conn]
}
func (slf *gNet) OnInitComplete(server gnet.Server) (action gnet.Action) {
slf.connections = synchronization.NewMap[string, *Conn]()
return
}
func (slf *gNet) OnShutdown(server gnet.Server) {
for k := range slf.connections.Map() {
slf.connections.Delete(k)
}
slf.connections = nil
}
func (slf *gNet) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
conn := newGNetConn(c)
slf.connections.Set(c.RemoteAddr().String(), conn)
slf.OnConnectionOpenedEvent(conn)
return
}
func (slf *gNet) OnClosed(c gnet.Conn, err error) (action gnet.Action) {
slf.OnConnectionClosedEvent(slf.connections.DeleteGet(c.RemoteAddr().String()))
slf.OnConnectionClosedEvent(newGNetConn(c))
return
}
@ -44,12 +37,8 @@ func (slf *gNet) AfterWrite(c gnet.Conn, b []byte) {
}
func (slf *gNet) React(packet []byte, c gnet.Conn) (out []byte, action gnet.Action) {
if conn, exist := slf.connections.GetExist(c.RemoteAddr().String()); exist {
slf.Server.PushMessage(MessageTypePacket, conn, packet)
return nil, gnet.None
} else {
return nil, gnet.Close
}
slf.Server.PushMessage(MessageTypePacket, newGNetConn(c), packet)
return nil, gnet.None
}
func (slf *gNet) Tick() (delay time.Duration, action gnet.Action) {

View File

@ -54,15 +54,14 @@ type Server struct {
httpServer *http.Server // HTTP模式下的服务器
grpcServer *grpc.Server // GRPC模式下的服务器
connections *synchronization.Map[string, *Conn] // 所有在线的连接
gServer *gNet // TCP或UDP模式下的服务器
messagePool *synchronization.Pool[*message] // 消息池
messagePoolSize int // 消息池大小
messageChannel chan *message // 消息管道
initMessageChannel bool // 消息管道是否已经初始化
multiple bool // 是否为多服务器模式下运行
prod bool // 是否为生产模式
core int // 消息处理核心数
gServer *gNet // TCP或UDP模式下的服务器
messagePool *synchronization.Pool[*message] // 消息池
messagePoolSize int // 消息池大小
messageChannel chan *message // 消息管道
initMessageChannel bool // 消息管道是否已经初始化
multiple bool // 是否为多服务器模式下运行
prod bool // 是否为生产模式
core int // 消息处理核心数
}
// Run 使用特定地址运行服务器
@ -85,7 +84,6 @@ func (slf *Server) Run(addr string) error {
slf.addr = addr
var protoAddr = fmt.Sprintf("%s://%s", slf.network, slf.addr)
var connectionInitHandle = func(callback func()) {
slf.connections = synchronization.NewMap[string, *Conn]()
slf.initMessageChannel = true
if slf.messagePoolSize <= 0 {
slf.messagePoolSize = 1024
@ -209,7 +207,7 @@ func (slf *Server) Run(addr string) error {
}
}
conn := newWebsocketConn(ws)
conn := newWebsocketConn(ws, ip)
slf.OnConnectionOpenedEvent(conn)
defer func() {
@ -273,11 +271,6 @@ func (slf *Server) IsDev() bool {
return !slf.prod
}
// GetConnections 获取所有在线的连接
func (slf *Server) GetConnections() synchronization.MapReadonly[string, *Conn] {
return slf.connections
}
// Shutdown 停止运行服务器
func (slf *Server) Shutdown(err error) {
if slf.initMessageChannel {
@ -288,9 +281,6 @@ func (slf *Server) Shutdown(err error) {
log.Error("Server", zap.Error(shutdownErr))
}
}
slf.connections.Range(func(connId string, conn *Conn) {
conn.Close()
})
close(slf.messageChannel)
slf.messagePool.Close()
slf.initMessageChannel = false