1. 程式人生 > 程式設計 >Zinx --基於Golang的輕量級併發伺服器框架

Zinx --基於Golang的輕量級併發伺服器框架

Zinx 是一個基於Golang的輕量級併發伺服器框架

說明:目前zinx已經在很多企業進行開發使用,具體使用領域包括:後端模組的訊息中轉、長連結遊戲伺服器、Web框架中的訊息處理外掛等。zinx的定位是程式碼簡潔,讓更多的開發者迅速的瞭解框架的內臟細節並且可以快速基於zinx DIY一款適合自己企業場景的模組。

開發者

zinx(C++版本)

開發者


Github

Git: github.com/aceld/zinx

碼雲(Gitee)

Git: gitee.com/Aceld/zinx


線上開發教程

[B站]

zinx-視訊教程B站

[YouTube]

zinx-youtube

一、寫在前面

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

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

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

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

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

zinx榮譽

開源中國GVP年度最有價值開源專案

GVP-zinx

二、初探Zinx架構

1-Zinx框架.png

zinx-start.gif

三、Zinx詳細教程及檔案

《Zinx框架教程-基於Golang的輕量級併發伺服器》

四、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,string(msg.Data))
		}

		time.Sleep(1*time.Second)
	}
}
複製程式碼

Zinx配置檔案

{
  "Name":"zinx v-0.10 demoApp","Host":"127.0.0.1","TcpPort":7777,"MaxConn":3,"WorkerPoolSize":10,"LogDir": "./mylog","LogFile":"zinx.log"
}
複製程式碼

Name:伺服器應用名稱

Host:伺服器IP

TcpPort:伺服器監聽埠

MaxConn:允許的客戶端連結最大數量

WorkerPoolSize:工作任務池最大工作Goroutine數量

LogDir: 日誌資料夾

LogFile: 日誌檔名稱(如果不提供,則日誌資訊列印到Stderr)

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: [email protected] github: github.com/aceld 原創書籍gitbook: legacy.gitbook.com/@aceld

Zinx技術討論社群

QQ技術討論群:

gopool5.jpeg

歡迎大家加入,獲取更多相關學習資料