专栏首页Golang语言社区[go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待

[go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待

设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,AccountServer会接收每个玩家的请求发送给帐号服务器验证合法性,然后把返回的结果分发给各个玩家。同时每个玩家goroutine在等待帐号验证的过程中需要阻塞等待

利用缓冲信道可以比较容易地实现这个特性。以下就是大致的代码结构,其中SendAndReceive函数被玩家goroutine调用并阻塞等待结果。该函数中利用缓冲信道来获取一个用于获得结果的信道,使用之后再回收。

type Msg struct {
    data []byte
    ch   chan []byte
}

type Connection interface {
    Write([]byte)
    Read() []byte
}

type AccountServer struct {
    conn Connection // 与帐号数据库服务器的网络链接
    tokens chan chan []byte
    msg    chan Msg
}

func NewAccountServer(conn Connection, maxclientcount int) *AccountServer {
    p := &AccountServer{}
    p.conn = conn 
    p.tokens = make(chan chan []byte, maxclientcount)
    p.msg = make(chan Msg, maxclientcount)
    for i := 0; i < maxclientcount; i++ {
        p.tokens <- make(chan []byte)
    }
    go p.run()
    return p
}

func (p *AccountServer) run() {
    rch := make(chan []byte)
    sch := make(chan []byte)
    go func() {
        for {p.conn.Write(<-sch)}
    }()
    go func() {
        for {rch <- p.conn.Read()}
    }()
    p.manage(sch, rch)
}

func (p *AccountServer) manage(sch chan<- []byte, rch <-chan []byte) {
    var id uint32
    players := make(map[uint32]chan []byte)
    for {
        select {
        case msg := <-p.msg:
            id++
            // 在数据包前面附上一个uint32,用于标识发送数据的玩家
            buff := make([]byte, 4+len(msg.data))
            buff[0] = byte(id & 0xff)
            buff[1] = byte((id >> 8) & 0xff)
            buff[2] = byte((id >> 16) & 0xff)
            buff[3] = byte((id >> 24) & 0xff)
            copy(buff[4:], msg.data)
            sch <- buff
            players[id] = msg.ch
        case data := <-rch:
            if len(data) <= 4 {
                break
            }
            // 从帐号数据库服务器返回的数据前四个字节会附带同样的uint32,,用于标识玩家
            var key uint32
            key = uint32(data[0])
            key |= uint32(data[1]) << 8
            key |= uint32(data[2]) << 16
            key |= uint32(data[3]) << 24
            ch, ok := players[key]
            if ok {
         ch <- data[4:]
       }
     }
    }
}
// 玩家对应的goroutine调用此函数向帐号服务器发送数据并等待返回
func (p *AccountServer) SendAndReceive(data []byte) []byte {
// 获取一个用于获取返回数据的信道
ch := <-p.tokens
// 回收信道
defer func() { p.tokens <- ch }()
p.msg <- Msg{data, ch}
return <-ch
}

本文分享自微信公众号 - Golang语言社区(Golangweb)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-02-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待

    设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,Acco...

    李海彬
  • 利用缓冲信道来实现网游帐号验证消息的分发和等待

    设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,Acco...

    李海彬
  • Golang语言 加密系列之AES

    加密代码: func Encrypt(plantText, key []byte) ([]byte, error) { block, err := aes...

    李海彬
  • 利用缓冲信道来实现网游帐号验证消息的分发和等待

    设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,Acco...

    李海彬
  • [go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待

    设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,Acco...

    李海彬
  • flume源码学习3-自动reload配

      在1.5.0的flume版本中开始提供这个功能,判断配置文件的更新时间戳来reload服务 原理: 1)在启动中使用EventBus.register注册A...

    py3study
  • 【转载】记Golang数据库查询封装的坑

    前文 golang接触也有一段时间,项目中有用到web api,基本上就是post json格式的,本想用java来写,刚下手想到java太臃肿,各种繁琐。觉得...

    李海彬
  • Go Reflect 理解

    最近在看一些go语言标准库以及第三方库的源码时,发现go的reflect被大量使用,虽然反射的机制大多数语言都支持,但好像都没有go一样这么依赖反射的特性。个人...

    李海彬
  • go笔记:json的简单处理

    json的本质就是数组和字典的组合,但系统的数组和字典都是确定类型的,所以,go的interface{}就能大显身手了。 下面的代码描述了自定义类型 List...

    超级大猪
  • 把3000行代码重构成15行,这样做!

    如果你认为这是一个标题党,那么我真诚的恳请你耐心的把文章的第一部分读完,然后再下结论。如果你认为能够戳中您的 G 点,那么请随手点个在看。

    数据和云

扫码关注云+社区

领取腾讯云代金券