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

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

說明:目前zinx已經在不少企業進行開發使用,具體使用領域包括:後端模塊的消息中轉、長連接遊戲服務器、Web框架中的消息處理插件等。zinx的定位是代碼簡潔,讓更多的開發者迅速的瞭解框架的內臟細節而且能夠快速基於zinx DIY一款適合本身企業場景的模塊。github

開發者

zinx(C++版本)json

開發者


Github

Git: github.com/aceld/zinx後端

碼雲(Gitee)

Git: gitee.com/Aceld/zinx服務器


在線開發教程

[B站]

zinx-視頻教程B站

[YouTube]

zinx-youtube

1、寫在前面

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

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

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

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

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

zinx榮譽

開源中國GVP年度最有價值開源項目

GVP-zinx

2、初探Zinx架構

1-Zinx框架.png

zinx-start.gif

3、Zinx詳細教程及文檔

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

4、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 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: danbing.at@gmail.com github: github.com/aceld 原創書籍gitbook: legacy.gitbook.com/@aceld

Zinx技術討論社區

QQ技術討論羣:

gopool5.jpeg

歡迎你們加入,獲取更多相關學習資料

相關文章
相關標籤/搜索