Go实现简单的Socket服务端笔记(十)

添加Session容器,增加超时自动关闭Session功能

本文代码查看github:
https://github.com/zboyco/go-server/tree/step-10


要实现超时管理,就需要有个地方保存所有的会话(session),我们采用 map 来存储所有的 session ,因为 session 的保存不需要顺序,同时也有删除和增加的功能,map 正好适合.

增加一个池结构,用map实现

1
2
3
4
type sessionSource struct {
source map[int64]*AppSession //Seesion池
mutex sync.Mutex //锁
}

再增加两个参数,分别用来设置超时时间和清理间隔

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Server 服务结构
type Server struct {
ip string //服务器IP
port int //服务器端口
clientCounter int64 //计数器
sessionSource *sessionSource //Seesion池
idleSessionTimeOut int //客户端空闲超时时间
clearIdleSessionInterval int //清空空闲会话的时间间隔,为0则不清理

OnError func(error) //错误方法
OnMessage func(*AppSession, []byte) //接收到新消息
OnNewSessionRegister func(*AppSession) //新客户端接入
OnSessionClosed func(*AppSession, string) //客户端关闭通知
}

server增加 注册session/周期性清理闲置Seesion/关闭session 三个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// registerSession 注册session
func (server *Server) registerSession(sessionID int64, appSession *AppSession) (bool, error) {
if server.sessionSource.source[sessionID] != nil {
return false, errors.New("SessionID已存在")
}

// 加入池
server.sessionSource.mutex.Lock()
server.sessionSource.source[sessionID] = appSession
server.sessionSource.mutex.Unlock()

// 新客户端接入通知
if server.OnNewSessionRegister != nil {
server.OnNewSessionRegister(appSession)
}

return true, nil
}
1
2
3
4
5
6
7
8
9
// closeSession 关闭session
func (server *Server) closeSession(session *AppSession, reason string) {
session.Close(reason)

// 从池中移除
server.sessionSource.mutex.Lock()
delete(server.sessionSource.source, session.ID)
server.sessionSource.mutex.Unlock()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// clearTimeoutSession 周期性清理闲置Seesion
func (server *Server) clearTimeoutSession(timeoutSecond int, interval int) {
var currentTime time.Time

if interval == 0 {
return
}

for {
time.Sleep(time.Duration(interval) * time.Second)

currentTime = time.Now()
server.mutex.Lock()
{
for key, session := range server.sessionSource {
if session.activeDateTime.Add(time.Duration(timeoutSecond) * time.Second).Before(currentTime) {
fmt.Println("客户端[", key, "]超时关闭")
session.Close("Timeout")
}
}
}
server.mutex.Unlock()
}
}