265 lines
6.2 KiB
Go
265 lines
6.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"mongo.games.com/goserver/core/module"
|
|
"mongo.games.com/goserver/core/netlib"
|
|
"mongo.games.com/goserver/srvlib"
|
|
)
|
|
|
|
var (
|
|
SessionHandlerBundleName = "handler-client-bundle"
|
|
BundleMgrSington = &BundleMgr{}
|
|
)
|
|
|
|
type SendPendItem struct {
|
|
sid int //当前pending包发给的session
|
|
packetid int
|
|
logicNo uint32
|
|
data interface{}
|
|
ts int64
|
|
}
|
|
|
|
type BundleSession struct {
|
|
bundleKey string
|
|
bundleSession []*netlib.Session
|
|
currentSession *netlib.Session
|
|
fastestSession *netlib.Session
|
|
worldsrvSession *netlib.Session
|
|
gamesrvSession *netlib.Session
|
|
waitAckChain []*SendPendItem
|
|
rcvLogicNo uint32
|
|
sndLogicNo uint32
|
|
lastSndTs int64
|
|
lastAckTs int64
|
|
RTT int64 //Round Trip Time
|
|
RTO int64 //Retransmission TimeOut
|
|
}
|
|
|
|
func (bs *BundleSession) OnSessionClose(s *netlib.Session) bool {
|
|
if bs.fastestSession == s {
|
|
bs.fastestSession = nil
|
|
}
|
|
if bs.currentSession == s {
|
|
bs.currentSession = nil
|
|
}
|
|
cnt := len(bs.bundleSession)
|
|
for i := 0; i < cnt; i++ {
|
|
if bs.bundleSession[i] == s {
|
|
if i == 0 {
|
|
bs.bundleSession = bs.bundleSession[1:]
|
|
} else if i == cnt-1 {
|
|
bs.bundleSession = bs.bundleSession[:cnt-1]
|
|
} else {
|
|
temp := bs.bundleSession[:i]
|
|
temp = append(temp, bs.bundleSession[i+1:]...)
|
|
bs.bundleSession = temp
|
|
}
|
|
break
|
|
}
|
|
}
|
|
//优先最快的一个连接
|
|
if bs.currentSession == nil {
|
|
bs.currentSession = bs.fastestSession
|
|
}
|
|
//从池里面挑选一个
|
|
if bs.currentSession == nil {
|
|
if len(bs.bundleSession) > 0 {
|
|
bs.currentSession = bs.bundleSession[0]
|
|
}
|
|
}
|
|
|
|
//重发没有回应的包
|
|
if bs.currentSession != nil {
|
|
idx := -1
|
|
for i, pack := range bs.waitAckChain {
|
|
if pack.sid == s.Id {
|
|
bs.currentSession.SendEx(pack.packetid, pack.logicNo, pack.data, false)
|
|
idx = i
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
if idx != -1 {
|
|
if idx < len(bs.waitAckChain) {
|
|
bs.waitAckChain = bs.waitAckChain[idx+1:]
|
|
}
|
|
}
|
|
} else { //所有连接都已关闭
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (bs *BundleSession) CacheSendItem(sid, packetid int, logicNo uint32, data interface{}) {
|
|
ts := module.AppModule.GetCurrTimeNano()
|
|
bs.waitAckChain = append(bs.waitAckChain, &SendPendItem{
|
|
sid: sid,
|
|
packetid: packetid,
|
|
logicNo: logicNo,
|
|
data: data,
|
|
ts: ts,
|
|
})
|
|
bs.lastSndTs = ts
|
|
}
|
|
|
|
func (bs *BundleSession) Send(packetid int, pack interface{}) {
|
|
if bs.currentSession != nil {
|
|
logicNo := atomic.AddUint32(&bs.sndLogicNo, 1)
|
|
if bs.currentSession.SendEx(packetid, logicNo, pack, false) {
|
|
bs.CacheSendItem(bs.currentSession.Id, packetid, logicNo, pack)
|
|
}
|
|
}
|
|
}
|
|
|
|
type BundleMgr struct {
|
|
freeBundle []uint16
|
|
bundles [math.MaxUint16]*BundleSession
|
|
bundlesMap map[string]uint16
|
|
Debug bool
|
|
}
|
|
|
|
// 主线程中调用
|
|
func (bm *BundleMgr) AllocBundleId() uint16 {
|
|
last := len(bm.freeBundle)
|
|
if last > 0 {
|
|
id := bm.freeBundle[last-1]
|
|
bm.freeBundle = bm.freeBundle[:last-1]
|
|
return id
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// 主线程中调用
|
|
func (bm *BundleMgr) FreeBundleId(id uint16) {
|
|
if bm.Debug {
|
|
for i := 0; i < len(bm.freeBundle); i++ {
|
|
if bm.freeBundle[i] == id {
|
|
panic(fmt.Sprintf("BundleMgr.FreeBundleId found repeat id:%v", id))
|
|
}
|
|
}
|
|
}
|
|
bm.freeBundle = append(bm.freeBundle, id)
|
|
delete(bm.bundlesMap, bm.bundles[id].bundleKey)
|
|
bm.bundles[id] = nil
|
|
}
|
|
|
|
// 主线程中调用
|
|
func (bm *BundleMgr) BindSession(bundleId uint16, s *netlib.Session) {
|
|
if bm.bundles[bundleId] == nil {
|
|
bm.bundles[bundleId] = &BundleSession{
|
|
RTO: int64(time.Second),
|
|
}
|
|
}
|
|
bs := bm.bundles[bundleId]
|
|
if bs != nil {
|
|
s.GroupId = int(bundleId)
|
|
param := s.GetAttribute(srvlib.SessionAttributeClientSession)
|
|
if param != nil {
|
|
if sid, ok := param.(srvlib.SessionId); ok {
|
|
s.Sid = int64(srvlib.NewSessionIdEx(int32(sid.AreaId()), int32(sid.SrvType()), int32(sid.SrvId()), int32(bundleId)))
|
|
}
|
|
}
|
|
|
|
bs.bundleSession = append(bs.bundleSession, s)
|
|
if bs.fastestSession == nil {
|
|
bs.fastestSession = s
|
|
}
|
|
if bs.currentSession == nil {
|
|
bs.currentSession = s
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bm *BundleMgr) GetBundleSession(bundleId uint16) *BundleSession {
|
|
return bm.bundles[bundleId]
|
|
}
|
|
|
|
// 主线程中调用
|
|
func (bm *BundleMgr) OnSessionAck(s *netlib.Session, logicNo uint32) {
|
|
if s != nil {
|
|
bs := bm.GetBundleSession(uint16(s.GroupId))
|
|
if bs != nil {
|
|
if len(bs.waitAckChain) > 0 && bs.waitAckChain[0].logicNo == logicNo {
|
|
pendingItem := bs.waitAckChain[0]
|
|
bs.waitAckChain = bs.waitAckChain[1:]
|
|
bs.fastestSession = s
|
|
if len(bs.waitAckChain) == 0 { //切换响应更快的链接
|
|
bs.currentSession = bs.fastestSession
|
|
}
|
|
bs.lastAckTs = module.AppModule.GetCurrTimeNano()
|
|
bs.RTT = bs.lastAckTs - pendingItem.ts
|
|
bs.RTO = bs.RTT * 5
|
|
if bs.RTO > int64(time.Second) { //最长1秒
|
|
bs.RTO = int64(time.Second)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bm *BundleMgr) Broadcast(packetid int, pack interface{}) {
|
|
for _, bid := range bm.bundlesMap {
|
|
bs := bm.GetBundleSession(bid)
|
|
if bs != nil {
|
|
bs.Send(packetid, pack)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bm *BundleMgr) ModuleName() string {
|
|
return "BundleMgr"
|
|
}
|
|
|
|
func (bm *BundleMgr) Init() {
|
|
bm.freeBundle = make([]uint16, 0, math.MaxUint16)
|
|
for i := uint16(math.MaxUint16); i > 0; i-- {
|
|
bm.freeBundle = append(bm.freeBundle, i)
|
|
}
|
|
bm.bundlesMap = make(map[string]uint16)
|
|
}
|
|
|
|
func (bm *BundleMgr) Update() {
|
|
ts := module.AppModule.GetCurrTimeNano()
|
|
for _, id := range bm.bundlesMap {
|
|
bs := bm.GetBundleSession(id)
|
|
if bs != nil {
|
|
if len(bs.waitAckChain) > 0 && ts-bs.waitAckChain[0].ts > bs.RTO { //重发
|
|
s := bs.fastestSession
|
|
if s == bs.currentSession {
|
|
for _, ss := range bs.bundleSession {
|
|
if s != ss {
|
|
s = ss
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if s != bs.currentSession {
|
|
bs.currentSession = s
|
|
chain := bs.waitAckChain
|
|
bs.waitAckChain = nil
|
|
for _, item := range chain {
|
|
if ts-item.ts > bs.RTO {
|
|
if bs.currentSession.SendEx(item.packetid, item.logicNo, item.data, false) {
|
|
bs.CacheSendItem(bs.currentSession.Id, item.packetid, item.logicNo, item.data)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bm *BundleMgr) Shutdown() {
|
|
module.UnregisteModule(bm)
|
|
}
|
|
|
|
func init() {
|
|
module.RegisteModule(BundleMgrSington, time.Millisecond*100, 0)
|
|
}
|