【Zinx第一章-引言】Golang輕量級併發服務器框架

【Zinx教程目錄】
Zinx源代碼
https://github.com/aceld/zinx
完整教程電子版(在線高清)-下載
Zinx框架視頻教程(框架篇)(完整版下載)連接在下面正文
Zinx框架視頻教程(應用篇)(完整版下載)連接在下面正文
Zinx開發API文檔
Zinx第一章-引言
Zinx第二章-初識Zinx框架
Zinx第三章-基礎路由模塊
Zinx第四章-全局配置
Zinx第五章-消息封裝
Zinx第六章-多路由模式
Zinx第七章-讀寫分離模型
Zinx第八章-消息隊列及多任務
Zinx第九章-連接管理
Zinx第十章-鏈接屬性設置git


【Zinx應用案例-MMO多人在線遊戲】
(1)案例介紹
(2)AOI興趣點算法
(3)數據傳輸協議protocol buffer
(4)Proto3協議定義
(5)構建項目及用戶上線
(6)世界聊天
(7)上線位置信息同步
(8)移動位置與AOI廣播
(9)玩家下線github


一、寫在前面

​ 咱們爲何要作Zinx,Golang目前在服務器的應用框架不少,可是應用在遊戲領域或者其餘長連接的領域的輕量級企業框架甚少。算法

​ 設計Zinx的目的是咱們能夠經過Zinx框架來了解基於Golang編寫一個TCP服務器的總體輪廓,讓更多的Golang愛好者能深刻淺出的去學習和認識這個領域。json

​ Zinx框架的項目製做採用編碼和學習教程同步進行,將開發的所有遞進和迭代思惟帶入教程中,而不是一會兒給你們一個很是完整的框架去學習,讓不少人一頭霧水,不知道該如何學起。服務器

​ 教程會一個版本一個版本迭代,每一個版本的添加功能都是微小的,讓一個服務框架小白,按部就班的曲線方式瞭解服務器框架的領域。架構

​ 固然,最後但願Zinx會有更多的人加入,給咱們提出寶貴的意見,讓Zinx成爲真正的解決企業的服務器框架!在此感謝您的關注!框架

2、初探Zinx架構

圖片描述

圖片描述

3、Zinx開發API文檔

快速開始

server

基於Zinx框架開發的服務器應用,主函數步驟比較精簡,最多主須要3步便可。socket

  1. 建立server句柄
  2. 配置自定義路由及業務
  3. 啓動服務
func main() {
    //1 建立一個server句柄
    s := znet.NewServer()

    //2 配置路由
    s.AddRouter(0, &PingRouter{})

    //3 開啓服務
    s.Serve()
}

其中自定義路由及業務配置方式以下:tcp

import (
    "fmt"
    "zinx/ziface"
    "zinx/znet"
)

//ping test 自定義路由
type PingRouter struct {
    znet.BaseRouter
}

//Ping Handle
func (this *PingRouter) Handle(request ziface.IRequest) {
    //先讀取客戶端的數據
    fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))

    //再回寫ping...ping...ping
    err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
    if err != nil {
        fmt.Println(err)
    }
}

client

Zinx的消息處理採用,[MsgLength]|[MsgID]|[Data]的封包格式函數

package main

import (
    "fmt"
    "io"
    "net"
    "time"
    "zinx/znet"
)

/*
    模擬客戶端
 */
func main() {

    fmt.Println("Client Test ... start")
    //3秒以後發起測試請求,給服務端開啓服務的機會
    time.Sleep(3 * time.Second)

    conn,err := net.Dial("tcp", "127.0.0.1:7777")
    if err != nil {
        fmt.Println("client start err, exit!")
        return
    }

    for n := 3; n >= 0; n-- {
        //發封包message消息
        dp := znet.NewDataPack()
        msg, _ := dp.Pack(znet.NewMsgPackage(0,[]byte("Zinx Client Test Message")))
        _, err := conn.Write(msg)
        if err !=nil {
            fmt.Println("write error err ", err)
            return
        }

        //先讀出流中的head部分
        headData := make([]byte, dp.GetHeadLen())
        _, err = io.ReadFull(conn, headData) //ReadFull 會把msg填充滿爲止
        if err != nil {
            fmt.Println("read head error")
            break
        }
        //將headData字節流 拆包到msg中
        msgHead, err := dp.Unpack(headData)
        if err != nil {
            fmt.Println("server unpack err:", err)
            return
        }

        if msgHead.GetDataLen() > 0 {
            //msg 是有data數據的,須要再次讀取data數據
            msg := msgHead.(*znet.Message)
            msg.Data = make([]byte, msg.GetDataLen())

            //根據dataLen從io中讀取字節流
            _, err := io.ReadFull(conn, msg.Data)
            if err != nil {
                fmt.Println("server unpack data err:", err)
                return
            }

            fmt.Println("==> Recv Msg: ID=", msg.Id, ", len=", msg.DataLen, ", data=", string(msg.Data))
        }

        time.Sleep(1*time.Second)
    }
}

Zinx配置文件

{
  "Name":"Zinx Game", 
  "Host":"0.0.0.0",
  "TcpPort":8999,
  "MaxConn":3000,
  "WorkerPoolSize":10
}

Name:服務器應用名稱
Host:服務器IP
TcpPort:服務器監聽端口
MaxConn:容許的客戶端連接最大數量
WorkerPoolSize:工做任務池最大工做Goroutine數量

I.服務器模塊Server

func NewServer () ziface.IServer

建立一個Zinx服務器句柄,該句柄做爲當前服務器應用程序的主樞紐,包括以下功能:

1) 開啓服務

func (s *Server) Start()

2) 中止服務

func (s *Server) Stop()

3) 運行服務

func (s *Server) Serve()

4) 註冊路由

func (s *Server) AddRouter (msgId uint32, router ziface.IRouter)

5) 註冊連接建立Hook函數

func (s *Server) SetOnConnStart(hookFunc func (ziface.IConnection))

6) 註冊連接銷燬Hook函數

func (s *Server) SetOnConnStop(hookFunc func (ziface.IConnection))

II. 路由模塊

//實現router時,先嵌入這個基類,而後根據須要對這個基類的方法進行重寫
type BaseRouter struct {}

//這裏之因此BaseRouter的方法都爲空,
// 是由於有的Router不但願有PreHandle或PostHandle
// 因此Router所有繼承BaseRouter的好處是,不須要實現PreHandle和PostHandle也能夠實例化
func (br *BaseRouter)PreHandle(req ziface.IRequest){}
func (br *BaseRouter)Handle(req ziface.IRequest){}
func (br *BaseRouter)PostHandle(req ziface.IRequest){}

III. 連接模塊

1) 獲取原始的socket TCPConn

func (c *Connection) GetTCPConnection() *net.TCPConn

2) 獲取連接ID

func (c *Connection) GetConnID() uint32

3) 獲取遠程客戶端地址信息

func (c *Connection) RemoteAddr() net.Addr

4) 發送消息

func (c *Connection) SendMsg(msgId uint32, data []byte) error 
  func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error

5) 連接屬性

//設置連接屬性
func (c *Connection) SetProperty(key string, value interface{})

//獲取連接屬性
func (c *Connection) GetProperty(key string) (interface{}, error)

//移除連接屬性
func (c *Connection) RemoveProperty(key string)

關於做者:

做者:Aceld(劉丹冰)

mail: danbing.at@gmail.com
github: https://github.com/aceld
原創書籍gitbook: http://legacy.gitbook.com/@aceld

原創聲明:未經做者容許請勿轉載,或者轉載請註明出處!
相關文章
相關標籤/搜索