Zinx --基于Golang的轻量级并发服务器框架
source link: https://studygolang.com/articles/24597
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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, ", 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
: [email protected] github
: github.com/aceld 原创书籍gitbook
: legacy.gitbook.com/@aceld
Recommend
-
3
knet 基于Golang的轻量级并发TCP框架 hXoreyer · 大约20小时之前 · 98 次点击 · 预计阅读时间 4...
-
50
本来自己打算继续学下beanFactory源码的,但是放假了自己也没什么精神,看源码又要求注意力很集中,所以想着看点简单点的内容吧,然后就想到了golang的另一个框架-Gin。假期过后可能就要开启加班生活了,不是很开心,昨天收到老大邮件,...
-
6
基于 .NET 6 的轻量级 Webapi 框架 FastEndpoints ...
-
5
并发是现代软件开发的一个基本概念,使程序能够同时执行多个任务。在 Go 编程领域,理解 Goroutines 是至关重要的。本文将全面概述 Goroutines,它们的轻量级特性,如何使用 go 关键字创建它们,以及它们提出的同步挑战,包括竞态条件和共享数据问题。
-
4
本文将介绍通过epoll实现的reactor并发模型的tcp服务。 更多请参考:我的自研网络框架 znet,欢迎Star与提Issue。 Reactor Reactor模式,是指通过一个或多个输入...
-
10
学习Golang之服务器框架编写 – 名字发现服务 2020/10/02 ·
-
5
学习Golang之服务器框架编写 – 开篇 2020/10/02 · Leave a c...
-
9
blue的配置功能实现在: https://github.com/lanyutc/blue/tree/master/conf blue的日志功能实现在:
-
1
写在前面 在 netty 框架面世之前,几乎没有一个成熟的OOP/组件化规范指导网络服务器开发,一些常用的 FrameDecoder , BusinessHandler 等等组件紧密耦合在了项目当中,整个项目...
-
42
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK