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

Aceld發表於2019-04-29

【Zinx 教程目錄】 Zinx 原始碼

https://github.com/aceld/zinx

完整教程電子版 (線上高清)-下載

Zinx 框架視訊教程 (框架篇)(完整版下載) 連結在下面正文

Zinx 框架視訊教程 (應用篇)(完整版下載) 連結在下面正文

Zinx 開發 API 文件

Zinx 第一章-引言

Zinx 第二章-初識 Zinx 框架

Zinx 第三章-基礎路由模組

Zinx 第四章-全域性配置

Zinx 第五章-訊息封裝

Zinx 第六章-多路由模式

Zinx 第七章-讀寫分離模型

Zinx 第八章-訊息佇列及多工

Zinx 第九章-連結管理

Zinx 第十章-連線屬性設定


【Zinx 應用案例-MMO 多人線上遊戲】

(1) 案例介紹

(2) AOI 興趣點演算法

(3) 資料傳輸協議 protocol buffer

(4) Proto3 協議定義

(5) 構建專案及使用者上線

(6) 世界聊天

(7) 上線位置資訊同步

(8) 移動位置與 AOI 廣播

(9) 玩家下線

1、寫在前面

​ 我們為什麼要做 Zinx,Golang 目前在伺服器的應用框架很多,但是應用在遊戲領域或者其他長連結的領域的輕量級企業框架甚少。

​ 設計 Zinx 的目的是我們可以通過 Zinx 框架來了解基於 Golang 編寫一個 TCP 伺服器的整體輪廓,讓更多的 Golang 愛好者能深入淺出的去學習和認識這個領域。

​ Zinx 框架的專案製作採用編碼和學習教程同步進行,將開發的全部遞進和迭代思維帶入教程中,而不是一下子給大家一個非常完整的框架去學習,讓很多人一頭霧水,不知道該如何學起。

​ 教程會一個版本一個版本迭代,每個版本的新增功能都是微小的,讓一個服務框架小白,循序漸進的曲線方式瞭解伺服器框架的領域。

​ 當然,最後希望 Zinx 會有更多的人加入,給我們提出寶貴的意見,讓 Zinx 成為真正的解決企業的伺服器框架!在此感謝您的關注!

二、初探 Zinx 架構

1-Zinx框架.png

zinx-start.gif

三、Zinx 開發 API 文件

快速開始

server

基於 Zinx 框架開發的伺服器應用,主函式步驟比較精簡,最多主需要 3 步即可。

  1. 建立 server 控制程式碼
  2. 配置自定義路由及業務
  3. 啟動服務
func main() {
    //1 建立一個server控制程式碼
    s := znet.NewServer()

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

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

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

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(劉丹冰) 簡書號:IT無崖子

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

>原創宣告:未經作者允許請勿轉載,或者轉載請註明出處!

更多原創文章乾貨分享,請關注公眾號
  • 【Zinx第一章-引言】Golang輕量級併發伺服器框架
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章