golang miniate gate server session管理(2)

1.思路

  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)
		}
	}()
}

源码地址,未经允许禁止转载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值