目录
前言
- 转载作者的语雀地址:https://www.yuque.com/aceld
- Zinx的Github —— Git: https://github.com/aceld/zinx
- 码云(Gitee) —— Git: https://gitee.com/Aceld/zinx
- 文章主要针对Zinx框架学习的总结
一、Zinx架构简介
- 为什么要做Zinx:引用作者原话“我们为什么要做Zinx,Golang目前在服务器的应用框架很多,但是应用在游戏领域或者其他长链接的领域的轻量级企业框架甚少”
- 设计Zinx的目的:引用作者原话“设计Zinx的目的是我们可以通过Zinx框架来了解基于Golang编写一个TCP服务器的整体轮廓,让更多的Golang爱好者能深入浅出的去学习和认识这个领域”
二、基础server实现思路
-
实现思路
-
项目目录结构
三、完整源码
1 - zinx/ziface/iserver.go
package ziface
//定义一个服务器接口
type IServer interface {
//启动服务器
Start()
//停止服务器
Stop()
//运行服务器
Serve()
}
2 - zinx/znet/server.go
package znet
import (
"fmt"
"net"
"zinx/ziface"
)
//iServer的接口实现,定义一个Server的服务器模块
type Server struct {
//服务器的名称
Name string
//服务器绑定的ip版本
IPVersion string
//服务器监听的IP
IP string
//服务器监听的端口
Port int
}
//启动服务器
func (s *Server) Start() {
fmt.Printf("[Start] Server Listenner at IP :%s, Port %d, is starting\n", s.IP, s.Port)
go func() {
// 1 获取一个TCP的Addr
addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
if err != nil {
fmt.Println("resolve tcp addt error : ", err)
return
}
//2 监听服务器的地址
listenner, err := net.ListenTCP(s.IPVersion, addr)
if err != nil {
fmt.Println("listen ", s.IPVersion, " err ", err)
return
}
fmt.Println("start Zinx server succ, ", s.Name, " succ, Listenning...")
//3 阻塞的等待客户端链接,处理客户端链接业务(读写)
for {
//如果有客户端链接过来,阻塞会返回
conn, err := listenner.AcceptTCP()
if err != nil {
fmt.Println("Accept err", err)
continue
}
//已经与客户端建立间接,做一些业务, 做一个最基本的最大512字节长度的回显业务
go func() {
for {
buf := make([]byte, 512)
cnt, err := conn.Read(buf)
if err != nil {
fmt.Println("recv buf err ", err)
continue
}
fmt.Printf("recv client buf %s, cnt %d\n", buf, cnt)
//回显功能
if _, err := conn.Write(buf[:cnt]); err != nil {
fmt.Println("write back buf err ", err)
continue
}
}
}()
}
}()
}
//停止服务器
func (s *Server) Stop() {
//TODO 将一些服务器的资源、状态或者一些已经开辟的链接信息 进行停止或者回收
}
//运行服务器
func (s *Server) Serve() {
//启动server的服务功能
s.Start()
//TODO 做一些启动服务器之后的额外业务
//阻塞状态
select {}
}
/*
初始化Server模块的方法
*/
func NewServer(name string) ziface.IServer {
s := &Server{
Name: name,
IPVersion: "tcp4",
IP: "0.0.0.0",
Port: 8999,
}
return s
}
3 - 测试类:server.go
package main
import "zinx/znet"
/*
基于Zinx框架来开发的 服务器端应用程序
*/
func main() {
//1 创建一个server句柄,使用Zinx的api
s := znet.NewServer("[zinx V0.1]")
//2 启动server
s.Serve()
}
4 - 测试类client.go
package main
import (
"fmt"
"net"
"time"
)
/*
模拟客户端
*/
func main() {
fmt.Println("client start...")
time.Sleep(1 * time.Second)
//1 直接链接远程服务器,得到一个conn链接
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
fmt.Println("client start err, exit!")
return
}
for {
//2 链接调用Write 写数据
_, err := conn.Write([]byte("Hello Zinx V0.1.."))
if err != nil {
fmt.Println("write conn err", err)
return
}
buf := make([]byte, 512)
cnt, err := conn.Read(buf)
if err != nil {
fmt.Println("read buf error")
return
}
fmt.Printf(" server call back: %s, cnt = %d\n", buf, cnt)
//cpu阻塞
time.Sleep(1 * time.Second)
}
}