[go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待
时间:2022-05-05
本文章向大家介绍[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
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php的无刷新操作实现方法分析
- PHP实现创建一个RPC服务操作示例
- php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
- gearman管理工具GearmanManager的安装与php使用方法示例
- php 的多进程操作实践案例分析
- php 输出缓冲 Output Control用法实例详解
- PHP使用gearman进行异步的邮件或短信发送操作详解
- php多进程并发编程防止出现僵尸进程的方法分析
- php+ajax实现文件切割上传功能示例
- php操作redis数据库常见方法实例总结
- php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
- PHP pthreads v3使用中的一些坑和注意点分析
- php ActiveMQ的安装与使用方法图文教程
- ThinkPHP5与单元测试PHPUnit使用详解
- php实现通过stomp协议连接ActiveMQ操作示例