1.思路
- 客户端连接到服务器,将connect包裹到session struct中,给session增加注销channel,decoder,send channel(用于接受conn.read的数据)
2.gate server
type GateServer struct {
base.BaseServer
conf *config
IdGeneral *snowflake.Node
//注销session的channel
unregister chan uint64
//接受session.read的数据channel
send chan *session.PostMsg
//路由
router *router.Router
sessionM *session.SyncClientMap
isDebug bool
}
2.启动tcp连接,创建session
func (s *GateServer) registerTcp() (err error) {
// 创建 listener
listener, err := net.Listen("tcp", fmt.Sprintf(":%s", s.conf.Tcp.Port))
err = errors.WithStack(err)
if err != nil {
//log.Fatalf(tag, "listening failed, err: %s", err.Error())
return
}
log.Infof(tag, "tcp listen :%s", s.conf.Tcp.Port)
// 监听并接受来自客户端的连接
go func() {
for {
conn, err := listener.Accept()
if err != nil {
log.Fatalf(tag, "accepting failed, err: %s", err.Error())
}
id := s.IdGeneral.Generate().Int64()
newSession := session.NewTcpSession(uint64(id), conn, s.unregister, s.send, s.router,
s.conf.Debug.IsCheckHeartbeat, s.conf.Debug.IsRecordHeartbeatLog)
newSession.Init()
newSession.ReadPump()
s.sessionM.Store(newSession.Id, newSession)
}
}()
return nil
}
3.统一注销
// unregisterRecv 统计处理session注销
func (s *GateServer) unregisterRecv() {
go func() {
for {
sessionId := <-s.unregister
session2 := s.sessionM.Load(sessionId)
if session2 == nil {
continue
}
err := session2.Close()
if err != nil {
log.Errorf(tag, "session2.Close failed, err: %+v", err)
continue
}
s.sessionM.Delete(sessionId)
log.Infof(tag, "[gate] unregister sid: %d, uid: %d", session2.GetId(), session2.GetUid())
}
}()
}
4. 统一处理conn.read数据
- 从channel中得到message数据,通过路由得到mq的exchange name,然后将数据投入mq
- 业务服只要从exchange中取出数据,再通过route key,就知道要执行哪个handlerFunc
func (s *GateServer) sendRecv() {
go func() {
for {
postMsg := <-s.send
session2 := s.sessionM.Load(postMsg.SessionId)
if session2 == nil {
return
}
for _, byts := range postMsg.MsgBytesList {
msg := message.NewMessageWithRouter(s.router)
err := msg.Decode(byts)
if err != nil {
log.Errorf(tag, "msg.Decode failed, err: %+v", err)
continue
}
exchangeName, ok := s.router.GetExchangeName(msg.Route)
if !ok {
_, err = log.ErrorfAndRetErr(tag, "illegal route %s", msg.Route)
s.generalResponseErr(session2, msg, err)
continue
}
log.Debugf(tag, "%c[1;0;36m [pub mq],msgId: %d, from sid: %d, msg: {type:%s route:%s exchange:%s}, %c[0m",
0x1B, msg.Id, postMsg.SessionId, msg.Type, msg.Route, exchangeName, 0x1B)
if !(msg.Type == message.Request || msg.Type == message.Notify) {
_, err = log.ErrorfAndRetErr(tag, "illegal message type %s from session id", msg.Type, msg.Id, postMsg.SessionId)
s.generalResponseErr(session2, msg, err)
continue
}
info := &gate.SendInfo{
Sid: postMsg.SessionId,
Body: byts,
}
body, err := proto.Marshal(info)
err = errors.WithStack(err)
if err != nil {
log.Errorf(tag, "proto.Marshal failed, err: %+v", err)
s.generalResponseErr(session2, msg, err)
continue
}
err = s.MQConn.PublishToTopic(s.Context, exchangeName, msg.Route, body)
if err != nil {
log.Errorf(tag, "MQConn.PublishToTopic failed, err: %+v", err)
s.generalResponseErr(session2, msg, err)
continue
}
}
}
}()
}
5.统一处理conne.write
// writeRecv businessServer中的handlerFunc处理结束后给session.write的数据
func (s *GateServer) writeRecv() {
go func() {
handlerFunc := func(delivery amqp.Delivery) {
defer func() {
err := delivery.Ack(true)
if err != nil {
log.Errorf(tag, "delivery.Ack failed, err: %+v", err)
}
}()
if len(delivery.Body) == 0 {
log.Errorf(tag, "delivery.Body len is 0")
return
}
ri := new(gate.ReceiveInfo)
err := proto.Unmarshal(delivery.Body, ri)
if err != nil {
err = errors.WithStack(err)
log.Errorf(tag, "proto.Unmarshal failed, err: %+v", err)
return
}
log.Debugf(tag, "%c[1;0;36m [sub mq] msgId %d, write to ri: {recvSids: %v, recvUids: %v}, msg: {type:%s, dataLen:%d}%c[0m",
0x1B, ri.MsgId, ri.ReceiverSids, ri.ReceiverUids, message.Type(ri.MsgType), len(ri.Body), 0x1B)
//根据sessionId,write数据
for _, id := range ri.ReceiverSids {
sessionInfo := s.sessionM.Load(id)
if sessionInfo == nil {
log.Infof(tag, "s.sessionM.Load failed, because sessionInfo id %d is nil", id)
continue
}
if s.conf.Debug.IsCheckHeartbeat {
err := sessionInfo.SetWriteDeadline(time.Now().Add(session.WriteLine))
if err != nil {
log.Errorf(tag, "sessionInfo.SetWriteDeadline failed, err: %+v", err)
continue
}
}
_, err = sessionInfo.Write(ri.Body)
if err != nil {
log.Errorf(tag, "sessionInfo.Write failed, err: %+v", err)
continue
}
}
根据uid找到对应的session,write数据
for _, uid := range ri.ReceiverUids {
session2 := s.sessionM.LoadWithUid(uid)
if session2 == nil {
log.Infof(tag, "s.sessionM.Load failed, because session2 id %d is nil", session2.GetId())
continue
}
if s.conf.Debug.IsCheckHeartbeat {
err := session2.SetWriteDeadline(time.Now().Add(session.WriteLine))
if err != nil {
log.Errorf(tag, "session2.SetWriteDeadline failed, err: %+v", err)
continue
}
}
_, err = session2.Write(ri.Body)
if err != nil {
log.Errorf(tag, "session2.Write failed, err: %+v", err)
continue
}
}
}
err := s.MQConn.SubscribeFromTopic(s.Context, rabbitmq.ExchangeGate, []string{rabbitmq.RouteWrite}, "",
handlerFunc)
if err != nil {
err = errors.WithStack(err)
log.Errorf(tag, "MQConn.SubscribeFromTopic failed, err: %+v", err)
}
}()
}
源码地址,未经允许禁止转载