分享
[go语言]利用缓冲信道来实现网游帐号验证消息的分发和等待
stevewang · · 3852 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,AccountServer会接收每个玩家的请求发送给帐号服务器验证合法性,然后把返回的结果分发给各个玩家。同时每个玩家goroutine在等待帐号验证的过程中需要阻塞等待。
利用缓冲信道可以比较容易地实现这个特性。以下就是大致的代码结构,其中SendAndReceive函数被玩家goroutine调用并阻塞等待结果。该函数中利用缓冲信道来获取一个用于获得结果的信道,使用之后再回收。
typeMsgstruct{
data[]byte
chchan[]byte
}
typeConnection interface{
Write([]byte)
Read()[]byte
}
typeAccountServerstruct{
conn Connection //与帐号数据库服务器的网络链接
tokenschanchan[]byte
msgchanMsg
}
funcNewAccountServer(connConnection,maxclientcountint)*AccountServer{
p:=&AccountServer{}
p.conn = conn
p.tokens=make(chanchan[]byte,maxclientcount)
p.msg=make(chanMsg,maxclientcount)
fori:=0;i<maxclientcount;i++{
p.tokens<-make(chan[]byte)
}
gop.run()
returnp
}
func(p*AccountServer)run(){
rch:=make(chan[]byte)
sch:=make(chan[]byte)
gofunc(){
for{p.conn.Write(<-sch)}
}()
gofunc(){
for{rch<-p.conn.Read()}
}()
p.manage(sch,rch)
}
func(p*AccountServer)manage(schchan<-[]byte,rch<-chan[]byte){
variduint32
players:=make(map[uint32]chan[]byte)
for{
select{
casemsg:=<-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
casedata:=<-rch:
iflen(data)<=4{
break
}
//从帐号数据库服务器返回的数据前四个字节会附带同样的uint32,,用于标识玩家
varkeyuint32
key=uint32(data[0])
key|=uint32(data[1])<<8
key|=uint32(data[2])<<16
key|=uint32(data[3])<<24
ch,ok:=players[key]
ifok{
ch <- data[4:]
}
}
}
}
// 玩家对应的goroutine调用此函数向帐号服务器发送数据并等待返回
func (p *AccountServer) SendAndReceive(data []byte) []byte {
func (p *AccountServer) SendAndReceive(data []byte) []byte {
//获取一个用于获取返回数据的信道
ch:=<-p.tokens
//回收信道
deferfunc(){p.tokens<-ch}()
p.msg<-Msg{data,ch}
return<-ch
}
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信3852 次点击
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
设想这样一个应用场景:一个网游登录服务器的实现里,每个玩家的连接用一个goroutine来处理,有一个主动对象AccountServer代表帐号服务器,AccountServer会接收每个玩家的请求发送给帐号服务器验证合法性,然后把返回的结果分发给各个玩家。同时每个玩家goroutine在等待帐号验证的过程中需要阻塞等待。
利用缓冲信道可以比较容易地实现这个特性。以下就是大致的代码结构,其中SendAndReceive函数被玩家goroutine调用并阻塞等待结果。该函数中利用缓冲信道来获取一个用于获得结果的信道,使用之后再回收。
typeMsgstruct{
data[]byte
chchan[]byte
}
typeConnection interface{
Write([]byte)
Read()[]byte
}
typeAccountServerstruct{
conn Connection //与帐号数据库服务器的网络链接
tokenschanchan[]byte
msgchanMsg
}
funcNewAccountServer(connConnection,maxclientcountint)*AccountServer{
p:=&AccountServer{}
p.conn = conn
p.tokens=make(chanchan[]byte,maxclientcount)
p.msg=make(chanMsg,maxclientcount)
fori:=0;i<maxclientcount;i++{
p.tokens<-make(chan[]byte)
}
gop.run()
returnp
}
func(p*AccountServer)run(){
rch:=make(chan[]byte)
sch:=make(chan[]byte)
gofunc(){
for{p.conn.Write(<-sch)}
}()
gofunc(){
for{rch<-p.conn.Read()}
}()
p.manage(sch,rch)
}
func(p*AccountServer)manage(schchan<-[]byte,rch<-chan[]byte){
variduint32
players:=make(map[uint32]chan[]byte)
for{
select{
casemsg:=<-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
casedata:=<-rch:
iflen(data)<=4{
break
}
//从帐号数据库服务器返回的数据前四个字节会附带同样的uint32,,用于标识玩家
varkeyuint32
key=uint32(data[0])
key|=uint32(data[1])<<8
key|=uint32(data[2])<<16
key|=uint32(data[3])<<24
ch,ok:=players[key]
ifok{
ch <- data[4:]
}
}
}
}
// 玩家对应的goroutine调用此函数向帐号服务器发送数据并等待返回
func (p *AccountServer) SendAndReceive(data []byte) []byte {
func (p *AccountServer) SendAndReceive(data []byte) []byte {
//获取一个用于获取返回数据的信道
ch:=<-p.tokens
//回收信道
deferfunc(){p.tokens<-ch}()
p.msg<-Msg{data,ch}
return<-ch
}