Zinx 是一個基於Golang的輕量級併發服務器框架git
說明:目前zinx已經在不少企業進行開發使用,具體使用領域包括:後端模塊的消息中轉、長連接遊戲服務器、Web框架中的消息處理插件等。zinx的定位是代碼簡潔,讓更多的開發者迅速的瞭解框架的內臟細節而且能夠快速基於zinx DIY一款適合本身企業場景的模塊。github
zinx(C++版本)json
Git: github.com/aceld/zinx後端
Git: gitee.com/Aceld/zinx服務器
咱們爲何要作Zinx,Golang目前在服務器的應用框架不少,可是應用在遊戲領域或者其餘長連接的領域的輕量級企業框架甚少。架構
設計Zinx的目的是咱們能夠經過Zinx框架來了解基於Golang編寫一個TCP服務器的總體輪廓,讓更多的Golang愛好者能深刻淺出的去學習和認識這個領域。併發
Zinx框架的項目製做採用編碼和學習教程同步進行,將開發的所有遞進和迭代思惟帶入教程中,而不是一會兒給你們一個很是完整的框架去學習,讓不少人一頭霧水,不知道該如何學起。框架
教程會一個版本一個版本迭代,每一個版本的添加功能都是微小的,讓一個服務框架小白,按部就班的曲線方式瞭解服務器框架的領域。socket
固然,最後但願Zinx會有更多的人加入,給咱們提出寶貴的意見,讓Zinx成爲真正的解決企業的服務器框架!在此感謝您的關注!tcp
zinx榮譽
基於Zinx框架開發的服務器應用,主函數步驟比較精簡,最多主須要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)
}
}
複製代碼
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)
}
}
複製代碼
{
"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)
func NewServer () ziface.IServer 複製代碼
建立一個Zinx服務器句柄,該句柄做爲當前服務器應用程序的主樞紐,包括以下功能:
func (s *Server) Start() 複製代碼
func (s *Server) Stop() 複製代碼
func (s *Server) Serve() 複製代碼
func (s *Server) AddRouter (msgId uint32, router ziface.IRouter) 複製代碼
func (s *Server) SetOnConnStart(hookFunc func (ziface.IConnection)) 複製代碼
func (s *Server) SetOnConnStop(hookFunc func (ziface.IConnection)) 複製代碼
//實現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){}
複製代碼
func (c *Connection) GetTCPConnection() *net.TCPConn 複製代碼
func (c *Connection) GetConnID() uint32 複製代碼
func (c *Connection) RemoteAddr() net.Addr 複製代碼
func (c *Connection) SendMsg(msgId uint32, data []byte) error func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error 複製代碼
//設置連接屬性
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
QQ技術討論羣:
歡迎你們加入,獲取更多相關學習資料