Zinx --基於Golang的輕量級併發伺服器框架
Zinx 是一個基於Golang的輕量級併發伺服器框架
說明:目前zinx已經在很多企業進行開發使用,具體使用領域包括:後端模組的訊息中轉、長連結遊戲伺服器、Web框架中的訊息處理外掛等。zinx的定位是程式碼簡潔,讓更多的開發者迅速的瞭解框架的內臟細節並且可以快速基於zinx DIY一款適合自己企業場景的模組。
開發者
開發者
- 劉洋(@marklion)
Github
碼雲(Gitee)
Git: gitee.com/Aceld/zinx
線上開發教程
[B站]
[YouTube]
一、寫在前面
我們為什麼要做Zinx,Golang目前在伺服器的應用框架很多,但是應用在遊戲領域或者其他長連結的領域的輕量級企業框架甚少。
設計Zinx的目的是我們可以通過Zinx框架來瞭解基於Golang編寫一個TCP伺服器的整體輪廓,讓更多的Golang愛好者能深入淺出的去學習和認識這個領域。
Zinx框架的專案製作採用編碼和學習教程同步進行,將開發的全部遞進和迭代思維帶入教程中,而不是一下子給大家一個非常完整的框架去學習,讓很多人一頭霧水,不知道該如何學起。
教程會一個版本一個版本迭代,每個版本的新增功能都是微小的,讓一個服務框架小白,循序漸進的曲線方式瞭解伺服器框架的領域。
當然,最後希望Zinx會有更多的人加入,給我們提出寶貴的意見,讓Zinx成為真正的解決企業的伺服器框架!在此感謝您的關注!
zinx榮譽
開源中國GVP年度最有價值開源專案
二、初探Zinx架構
三、Zinx詳細教程及檔案
四、Zinx開發API檔案
快速開始
server
基於Zinx框架開發的伺服器應用,主函式步驟比較精簡,最多主需要3步即可。
- 建立server控制程式碼
- 配置自定義路由及業務
- 啟動服務
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技術討論群:
歡迎大家加入,獲取更多相關學習資料