97 lines
2.6 KiB
Go
97 lines
2.6 KiB
Go
// 该案例中将服务器消息通过多核的方式异步传输到房间中,在每个房间中单独同步处理维护消息。
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/kercylan98/minotaur/game/builtin"
|
|
"github.com/kercylan98/minotaur/server"
|
|
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type message struct {
|
|
conn *server.Conn
|
|
packet []byte
|
|
}
|
|
|
|
type Room struct {
|
|
*builtin.Room[string, *builtin.Player[string]]
|
|
channel chan *message // need close
|
|
pool *synchronization.Pool[*message]
|
|
}
|
|
|
|
func newRoom(guid int64) *Room {
|
|
room := &Room{
|
|
Room: builtin.NewRoom[string, *builtin.Player[string]](guid),
|
|
}
|
|
room.pool = synchronization.NewPool[*message](1024*100, func() *message {
|
|
return new(message)
|
|
}, func(data *message) {
|
|
data.conn = nil
|
|
data.packet = nil
|
|
})
|
|
room.channel = make(chan *message, 1024*100)
|
|
go func() {
|
|
for msg := range room.channel {
|
|
room.handePacket(msg.conn, msg.packet)
|
|
room.pool.Release(msg)
|
|
}
|
|
}()
|
|
return room
|
|
}
|
|
|
|
func (slf *Room) PushMessage(conn *server.Conn, packet []byte) {
|
|
msg := slf.pool.Get()
|
|
msg.conn = conn
|
|
msg.packet = packet
|
|
slf.channel <- msg
|
|
}
|
|
|
|
func (slf *Room) handePacket(conn *server.Conn, packet []byte) {
|
|
conn.WriteString(fmt.Sprintf("[%d] %s", slf.GetGuid(), string(packet)))
|
|
}
|
|
|
|
// 以房间为核心玩法的多核服务器实现
|
|
// - 服务器消息处理为异步执行
|
|
// - 由房间分发具体消息,在房间内所有消息为同步执行
|
|
func main() {
|
|
rooms := synchronization.NewMap[int64, *Room]()
|
|
|
|
srv := server.New(server.NetworkWebsocket,
|
|
server.WithWebsocketWriteMessageType(server.WebsocketMessageTypeText),
|
|
server.WithMultiCore(10),
|
|
)
|
|
|
|
srv.RegConnectionReceiveWebsocketPacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte, messageType int) {
|
|
p := strings.SplitN(string(packet), ":", 2)
|
|
roomId, err := strconv.ParseInt(p[0], 10, 64)
|
|
if err != nil {
|
|
conn.WriteString(fmt.Sprintf("wrong room id, err: %s", err.Error()))
|
|
return
|
|
}
|
|
// 假定命令格式 ${房间ID}:命令
|
|
switch p[1] {
|
|
case "create":
|
|
if !rooms.Exist(roomId) {
|
|
rooms.Set(roomId, newRoom(roomId))
|
|
conn.WriteString(fmt.Sprintf("create room[%d] success", roomId))
|
|
} else {
|
|
conn.WriteString(fmt.Sprintf("room[%d] existed", roomId))
|
|
}
|
|
default:
|
|
room, exist := rooms.GetExist(roomId)
|
|
if !exist {
|
|
rooms.Set(roomId, room)
|
|
conn.WriteString(fmt.Sprintf("room[%d] does not exist, create room please use ${roomId}:create", roomId))
|
|
} else {
|
|
room.PushMessage(conn, []byte(p[1]))
|
|
}
|
|
}
|
|
})
|
|
|
|
if err := srv.Run(":9999"); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|