房间类游戏后台框架(三)—大厅服务器

  大厅服务器概述

  大厅服务器负责玩家进入游戏的接入、发送公告等功能。当玩家登陆完毕、游戏结束后将会进入大厅服务器。

  大厅服务器需求

  1. 公告
  2. 对玩家进行匹配
  3. 创建房间
  4. 加入房间

  大厅服务器结构

  大厅服务器流程

    

    大厅服务器细节

    由于使用了Redis当作全局内存,其实游戏大厅只是一个使用Redis进行业务操作的模块。在线匹配功能后期可以划分为匹配服务器,降低游戏大厅负载。

    在创建房间过程中,大厅服务器对在线的游戏服务进行遍历,负载低的服务器优先创建房间。

    由于使用了消息队列,因此并不能同步发送信息,因此写了组件专门处理使异步操作使其变为同步操作,代码如下:

type BlockVisit struct {
	Message map[string]chan grpc_common.Message
	sync.RWMutex
}

func (block *BlockVisit) Get(name string) (chan grpc_common.Message, error) {
	block.RLock()
	defer block.RUnlock()
	message, exit := block.Message[name]
	if !exit {
		return nil, errors.New("error messageid")
	}
	return message, nil
}

func (block *BlockVisit) GrpcSend(client *Grpc_client, Message grpc_common.MessageRouter, timeout int) (grpc_common.Message, error) {

	// 设置信息为发送出去处理
	Message.RouteMessage.DealMessage = true
	message := make(chan grpc_common.Message, 1)
	block.Lock()
	MessageId := block.NewId()
	block.Message[MessageId] = message
	Message.RouteMessage.MessageId = MessageId
	sendmessage, err := grpc_common.Encode(&Message)
	if err != nil {
		return grpc_common.Message{}, err
	}
	err = client.WriteMessage(sendmessage)
	if err != nil {
		delete(block.Message, MessageId)
		block.Unlock()
		return grpc_common.Message{}, err
	}
	block.Unlock()
	timer := time.NewTicker(time.Duration(timeout) * time.Second)
	select {
	case <-timer.C:
		block.Lock()
		delete(block.Message, MessageId)
		block.Unlock()
		return grpc_common.Message{}, errors.New("Time out")
	case m := <-message:
		block.Lock()
		delete(block.Message, MessageId)
		block.Unlock()
		if m.GetName() == MessageNotFindItem {
			return grpc_common.Message{}, errors.New(MessageNotFindItem)
		}
		return m, nil
	}
}

func (block *BlockVisit) RabbitmqSend(client *RabbitMq,Message grpc_common.Message,Item string,timeout int)(*grpc_common.Message,error){
	Message.DealMessage = true
	MessageChan := make(chan grpc_common.Message, 1)
	block.Lock()
	MessageId := block.NewId()
	block.Message[MessageId] = MessageChan
	Message.MessageId = MessageId
	block.Unlock()
	MessageData,err:= proto.Marshal(&Message)
	if err!=nil{
		return nil,err
	}
	client.Publish(Item,MessageData)
	timer := time.NewTicker(time.Duration(timeout) * time.Second)
	select {
	case <-timer.C:
		block.Lock()
		delete(block.Message, MessageId)
		block.Unlock()
		return nil, errors.New("Time out")
	case m := <-MessageChan:
		block.Lock()
		delete(block.Message, MessageId)
		block.Unlock()
		return &m,nil
    }
}

// 使用需上锁
func (block *BlockVisit) NewId() string {
	var ID string
	for true {
		ID = GetRandomString(10)
		_, exit := block.Message[ID]
		if !exit {
			return ID
		}
	}
	return ""
}

func GetRandomString(l int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyz"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

    原理很简单,为发送的信息生成唯一ID,并将其ID对应一个channel。当发送出去时启动一个定时器,当定时器超时返回错误。如果接收到对应ID,则将其信息通过channel发送给正处于定时状态的函数,接收到信息的函数将结果返回。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值