Zinx基于 Go 的輕量級(jí)并發(fā)服務(wù)器框架
Zinx 是一個(gè)基于Golang的輕量級(jí)并發(fā)服務(wù)器框架
開發(fā)人員
一、寫在前面
我們?yōu)槭裁匆鯶inx,Golang目前在服務(wù)器的應(yīng)用框架很多,但是應(yīng)用在游戲領(lǐng)域或者其他長(zhǎng)鏈接的領(lǐng)域的輕量級(jí)企業(yè)框架甚少。
設(shè)計(jì)Zinx的目的是我們可以通過Zinx框架來(lái)了解基于Golang編寫一個(gè)TCP服務(wù)器的整體輪廓,讓更多的Golang愛好者能深入淺出的去學(xué)習(xí)和認(rèn)識(shí)這個(gè)領(lǐng)域。
Zinx框架的項(xiàng)目制作采用編碼和學(xué)習(xí)教程同步進(jìn)行,將開發(fā)的全部遞進(jìn)和迭代思維帶入教程中,而不是一下子給大家一個(gè)非常完整的框架去學(xué)習(xí),讓很多人一頭霧水,不知道該如何學(xué)起。
教程會(huì)一個(gè)版本一個(gè)版本迭代,每個(gè)版本的添加功能都是微小的,讓一個(gè)服務(wù)框架小白,循序漸進(jìn)的曲線方式了解服務(wù)器框架的領(lǐng)域。
當(dāng)然,最后希望Zinx會(huì)有更多的人加入,給我們提出寶貴的意見,讓Zinx成為真正的解決企業(yè)的服務(wù)器框架!在此感謝您的關(guān)注!
二、初探Zinx架構(gòu)
三、Zinx詳細(xì)教程(代碼教程同步更新)
《Zinx框架教程-基于Golang的輕量級(jí)并發(fā)服務(wù)器》
四、Zinx開發(fā)API文檔
快速開始
server
基于Zinx框架開發(fā)的服務(wù)器應(yīng)用,主函數(shù)步驟比較精簡(jiǎn),最多主需要3步即可。
1. 創(chuàng)建server句柄
2. 配置自定義路由及業(yè)務(wù)
3. 啟動(dòng)服務(wù)
func main() {
//1 創(chuàng)建一個(gè)server句柄
s := znet.NewServer()
//2 配置路由
s.AddRouter(0, &PingRouter{})
//3 開啟服務(wù)
s.Serve()
}
其中自定義路由及業(yè)務(wù)配置方式如下:
import (
"fmt"
"zinx/ziface"
"zinx/znet"
)
//ping test 自定義路由
type PingRouter struct {
znet.BaseRouter
}
//Ping Handle
func (this *PingRouter) Handle(request ziface.IRequest) {
//先讀取客戶端的數(shù)據(jù)
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秒之后發(fā)起測(cè)試請(qǐng)求,給服務(wù)端開啟服務(wù)的機(jī)會(huì)
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-- {
//發(fā)封包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 會(huì)把msg填充滿為止
if err != nil {
fmt.Println("read head error")
break
}
//將headData字節(jié)流 拆包到msg中
msgHead, err := dp.Unpack(headData)
if err != nil {
fmt.Println("server unpack err:", err)
return
}
if msgHead.GetDataLen() > 0 {
//msg 是有data數(shù)據(jù)的,需要再次讀取data數(shù)據(jù)
msg := msgHead.(*znet.Message)
msg.Data = make([]byte, msg.GetDataLen())
//根據(jù)dataLen從io中讀取字節(jié)流
_, 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`:服務(wù)器應(yīng)用名稱
`Host`:服務(wù)器IP
`TcpPort`:服務(wù)器監(jiān)聽端口
`MaxConn`:允許的客戶端鏈接最大數(shù)量
`WorkerPoolSize`:工作任務(wù)池最大工作Goroutine數(shù)量
I.服務(wù)器模塊Server
func NewServer () ziface.IServer
創(chuàng)建一個(gè)Zinx服務(wù)器句柄,該句柄作為當(dāng)前服務(wù)器應(yīng)用程序的主樞紐,包括如下功能:
1)開啟服務(wù)
func (s *Server) Start()
2)停止服務(wù)
func (s *Server) Stop()
3)運(yùn)行服務(wù)
func (s *Server) Serve()
4)注冊(cè)路由
func (s *Server) AddRouter (msgId uint32, router ziface.IRouter)
5)注冊(cè)鏈接創(chuàng)建Hook函數(shù)
func (s *Server) SetOnConnStart(hookFunc func (ziface.IConnection))
6)注冊(cè)鏈接銷毀Hook函數(shù)
func (s *Server) SetOnConnStop(hookFunc func (ziface.IConnection))
II.路由模塊
//實(shí)現(xiàn)router時(shí),先嵌入這個(gè)基類,然后根據(jù)需要對(duì)這個(gè)基類的方法進(jìn)行重寫
type BaseRouter struct {}
//這里之所以BaseRouter的方法都為空,
// 是因?yàn)橛械腞outer不希望有PreHandle或PostHandle
// 所以Router全部繼承BaseRouter的好處是,不需要實(shí)現(xiàn)PreHandle和PostHandle也可以實(shí)例化
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)獲取遠(yuǎn)程客戶端地址信息
func (c *Connection) RemoteAddr() net.Addr
4)發(fā)送消息
func (c *Connection) SendMsg(msgId uint32, data []byte) error
func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error
5)鏈接屬性
//設(shè)置鏈接屬性
func (c *Connection) SetProperty(key string, value interface{})
//獲取鏈接屬性
func (c *Connection) GetProperty(key string) (interface{}, error)
//移除鏈接屬性
func (c *Connection) RemoveProperty(key string)
mail: [email protected]
github: https://github.com/aceld
原創(chuàng)書籍gitbook: http://legacy.gitbook.com/@aceld
