网络编程中的Go语言协程

图1

上图中,假设有N个客户端,那么网络模块就会开2*N个Go协程。

如果有C/C++编程基础的人,可能会感到疑惑,这种网络库模型是否有问题。

这显然受到多线程编程经验的影响了!

协程通过在线程中实现调度,避免了陷入内核级别的上下文切换造成的性能损失。即协程切换时,线程没有被切出去。

代价就是1个协程需要不少内存,至少8K。即通过空间换时间的方式来模拟多线程编程模式

理解Go协程,最简单的方式是,想象每个线程上都有1个协程队列,1个协程要执行阻塞操作了,就把这个协程插到本队列最后,线程没有被切换,且下个协程得到执行。

重点提示:这里的网络Go协程模型,适用于任何多任务阻塞模块

base/gonet

base/gonet库的实现方式,就是上节提到的编程模型。

使用base/gonet的例子可以参见:mope\server\src\base\gonet\examples

也可以直接看mope项目中如何使用base/gonet

项目中网络模块代码分析 - roomserver.go

roomserver.go 中,包含了启动网络模块,以及接受建立网络会话

  • 启动监听端口

    func (this *RoomServer) Init() bool {
    // ... (无关代码略)
    
    // 绑定本地端口
    port := env.Get("room", "listen")
    err := this.roomser.Bind(port)
    if err != nil {
      glog.Error("[启动] 绑定端口失败")
      return false
    }
    
    // ... (无关代码略)
    }
    
  • 接受建立网络会话

    func (this *RoomServer) MainLoop() {
    conn, err := this.roomser.Accept()
    if err != nil {
        return
    }
    tcptask.NewPlayerTask(conn).Start()
    }
    

    每个会话会开2个go协程

项目中网络模块代码分析 - PlayerTask.go

PlayerTask.go,表示一个网络会话

  • 继承gonet.TcpTask

    type PlayerTask struct {
    gonet.TcpTask                  // tcp会话
    // ... (无关代码略)
    }
    
  • 网络数据到达事件

    func (this *PlayerTask) ParseMsg(data []byte, flag byte) bool {
    cmd := usercmd.MsgTypeCmd(common.GetCmd(data))
    if !this.IsVerified() {
        return this.LoginVerify(cmd, data, flag)
    }
    
    // ... (无关代码略)
    
    if cmd == usercmd.MsgTypeCmd_HeartBeat {
        this.AsyncSend(data, flag)
        return true
    }
    
    // ... (无关代码略)
    
    return true
    }
    

    该函数会被自动触发,当网络数据到达后

    base/gonet特别规定了,网络会话建立后,第一个消息为验证消息,处理完毕后,需要调用gonet.TcpTask.Verify(),否则会被视作验证操作,导致连接被关闭

  • 发送protobuf消息接口

    func (this *PlayerTask) SendCmd(cmd usercmd.MsgTypeCmd, msg common.Message) error {
    data, flag, err := common.EncodeGoCmd(uint16(cmd), msg)
    if err != nil {
        glog.Info("[玩家] 发送失败 cmd:", cmd, ",len:", len(data), ",err:", err)
        return err
    }
    this.AsyncSend(data, flag)
    return nil
    }
    

项目中网络模块代码分析 - PlayerTaskMgr.go

PlayerTaskMgr.go,管理客户端网络会话。

如定期检查踢出非活跃连接。

代码很简单,不再细讲。

results matching ""

    No results matching ""