Browse Source

添加快速启动Demo演示示例

master
aceld 4 years ago
parent
commit
a4fcd9f69a
  1. 55
      README.md
  2. 63
      examples/zinx_client/main.go
  3. 9
      examples/zinx_server/conf/zinx.json
  4. 60
      examples/zinx_server/main.go
  5. 24
      examples/zinx_server/zrouter/hello.go
  6. 25
      examples/zinx_server/zrouter/ping.go
  7. 35
      makefile
  8. 8
      utils/globalobj.go
  9. 9
      znet/server.go
  10. 7
      ztimer/timerscheduler_test.go

55
README.md

@ -1,5 +1,5 @@
# <img width="80px" src="https://s2.ax1x.com/2019/10/09/u4yHo9.png" /> # <img width="80px" src="https://s2.ax1x.com/2019/10/09/u4yHo9.png" />
[![License](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE) [![Gitter](https://img.shields.io/badge/在线交流-Gitter-green.svg)](https://gitter.im/zinx_go/community) [![zinx详细教程](https://img.shields.io/badge/zinx详细教程-简书-red.svg)](https://www.jianshu.com/p/23d07c0a28e5) [![zinx原创书籍下载](https://img.shields.io/badge/原创书籍下载-Gitbook-black.svg)](https://legacy.gitbook.com/book/aceld/zinx/details)
[![License](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE) [![Gitter](https://img.shields.io/badge/在线交流-Gitter-green.svg)](https://gitter.im/zinx_go/community) [![zinx详细教程](https://img.shields.io/badge/zinx详细教程-简书-red.svg)](https://www.kancloud.cn/aceld/zinx) [![zinx原创书籍下载](https://img.shields.io/badge/原创书籍下载-KanCloud-black.svg)](https://www.kancloud.cn/@aceld)
Zinx 是一个基于Golang的轻量级并发服务器框架 Zinx 是一个基于Golang的轻量级并发服务器框架
@ -91,6 +91,59 @@ Zinx框架的项目制作采用编码和学习教程同步进行,将开发的
### 快速开始 ### 快速开始
#### 示例演示
1. 编译demo示例,会在`zinx/example/zinx_server`下得到`server`, 在`zinx/example/zinx_client`下得到`client`.
```bash
$ cd zinx/
$ make
```
2. 启动Demo server, 该终端不要关闭
```bash
$ cd example/zinx_server
$ ./server
██
▀▀
████████ ████ ██▄████▄ ▀██ ██▀
▄█▀ ██ ██▀ ██ ████
▄█▀ ██ ██ ██ ▄██▄
▄██▄▄▄▄▄ ▄▄▄██▄▄▄ ██ ██ ▄█▀▀█▄
▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀ ▀▀ ▀▀▀ ▀▀▀
┌───────────────────────────────────────────────────┐
│ [Github] https://github.com/aceld │
│ [tutorial] https://www.kancloud.cn/aceld/zinx │
└───────────────────────────────────────────────────┘
[Zinx] Version: V0.11, MaxConn: 3, MaxPacketSize: 4096
Add api msgId = 0
Add api msgId = 1
[START] Server name: zinx server Demo,listenner at IP: 127.0.0.1, Port 8999 is starting
Worker ID = 0 is started.
Worker ID = 1 is started.
Worker ID = 2 is started.
Worker ID = 3 is started.
Worker ID = 4 is started.
Worker ID = 7 is started.
Worker ID = 6 is started.
Worker ID = 8 is started.
Worker ID = 9 is started.
Worker ID = 5 is started.
start Zinx server zinx server Demo succ, now listenning...
...
```
3. 再打开新终端,启动client Demo测试通信
```bash
$ cd example/zinx_client
$ ./client
==> Test Router:[Ping] Recv Msg: ID= 2 , len= 21 , data= DoConnection BEGIN... ==> Test Router:[Ping] Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
==> Test Router:[Ping] Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
==> Test Router:[Ping] Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
...
t
```
#### server #### server
基于Zinx框架开发的服务器应用,主函数步骤比较精简,最多只需要3步即可。 基于Zinx框架开发的服务器应用,主函数步骤比较精简,最多只需要3步即可。
1. 创建server句柄 1. 创建server句柄

63
examples/zinx_client/main.go

@ -0,0 +1,63 @@
package main
import (
"fmt"
"github.com/aceld/zinx/znet"
"io"
"net"
"time"
)
/*
模拟客户端
*/
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
fmt.Println("client start err, exit!")
return
}
for {
//发封包message消息
dp := znet.NewDataPack()
msg, _ := dp.Pack(znet.NewMsgPackage(0, []byte("Zinx client Demo Test MsgID=0, [Ping]")))
_, 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("==> Test Router:[Ping] Recv Msg: ID=", msg.Id, ", len=", msg.DataLen, ", data=", string(msg.Data))
}
time.Sleep(1 * time.Second)
}
}

9
examples/zinx_server/conf/zinx.json

@ -0,0 +1,9 @@
{
"Name":"zinx server Demo",
"Host":"127.0.0.1",
"TcpPort":8999,
"MaxConn":3,
"WorkerPoolSize":10,
"LogDir": "./mylog",
"LogFile":"zinx.log"
}

60
examples/zinx_server/main.go

@ -0,0 +1,60 @@
/**
* @Author: Aceld
* @Date: 2020/12/24 00:24
* @Mail: danbing.at@gmail.com
* zinx server demo
*/
package main
import (
"github.com/aceld/zinx/examples/zinx_server/zrouter"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
)
//创建连接的时候执行
func DoConnectionBegin(conn ziface.IConnection) {
zlog.Debug("DoConnecionBegin is Called ... ")
//设置两个链接属性,在连接创建之后
zlog.Debug("Set conn Name, Home done!")
conn.SetProperty("Name", "Aceld")
conn.SetProperty("Home", "https://www.jianshu.com/u/35261429b7f1")
err := conn.SendMsg(2, []byte("DoConnection BEGIN..."))
if err != nil {
zlog.Error(err)
}
}
//连接断开的时候执行
func DoConnectionLost(conn ziface.IConnection) {
//在连接销毁之前,查询conn的Name,Home属性
if name, err := conn.GetProperty("Name"); err == nil {
zlog.Error("Conn Property Name = ", name)
}
if home, err := conn.GetProperty("Home"); err == nil {
zlog.Error("Conn Property Home = ", home)
}
zlog.Debug("DoConneciotnLost is Called ... ")
}
func main() {
//创建一个server句柄
s := znet.NewServer()
//注册链接hook回调函数
s.SetOnConnStart(DoConnectionBegin)
s.SetOnConnStop(DoConnectionLost)
//配置路由
s.AddRouter(0, &zrouter.PingRouter{})
s.AddRouter(1, &zrouter.HelloZinxRouter{})
//开启服务
s.Serve()
}

24
examples/zinx_server/zrouter/hello.go

@ -0,0 +1,24 @@
package zrouter
import (
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
)
type HelloZinxRouter struct {
znet.BaseRouter
}
//HelloZinxRouter Handle
func (this *HelloZinxRouter) Handle(request ziface.IRequest) {
zlog.Debug("Call HelloZinxRouter Handle")
//先读取客户端的数据,再回写ping...ping...ping
zlog.Debug("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
err := request.GetConnection().SendBuffMsg(1, []byte("Hello Zinx Router V0.10"))
if err != nil {
zlog.Error(err)
}
}

25
examples/zinx_server/zrouter/ping.go

@ -0,0 +1,25 @@
package zrouter
import (
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
)
//ping test 自定义路由
type PingRouter struct {
znet.BaseRouter
}
//Ping Handle
func (this *PingRouter) Handle(request ziface.IRequest) {
zlog.Debug("Call PingRouter Handle")
//先读取客户端的数据,再回写ping...ping...ping
zlog.Debug("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
if err != nil {
zlog.Error(err)
}
}

35
makefile

@ -1,11 +1,28 @@
# gofmt格式化
# run in terminal:
# make fmt
# win系统中,在git bash中如果出现make包没有找到
# 管理员运行git bash,运行以下命令
# choco install make
GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
.PHONY: build
fmt:
gofmt -w $(GOFMT_FILES)
SERVICE := zinx
CUR_PWD := $(shell pwd)
SERVER_DEMO_PATH := $(CUR_PWD)/examples/zinx_server
CLIENT_DEMO_PATH := $(CUR_PWD)/examples/zinx_client
SERVER_DEMO_BIN := $(SERVER_DEMO_PATH)/server
CLIENT_DEMO_BIN := $(CLIENT_DEMO_PATH)/client
AUTHOR := $(shell git log --pretty=format:"%an"|head -n 1)
VERSION := $(shell git rev-list HEAD | head -1)
BUILD_INFO := $(shell git log --pretty=format:"%s" | head -1)
BUILD_DATE := $(shell date +%Y-%m-%d\ %H:%M:%S)
export GO111MODULE=on
LD_FLAGS='-X "$(SERVICE)/version.TAG=$(TAG)" -X "$(SERVICE)/version.VERSION=$(VERSION)" -X "$(SERVICE)/version.AUTHOR=$(AUTHOR)" -X "$(SERVICE)/version.BUILD_INFO=$(BUILD_INFO)" -X "$(SERVICE)/version.BUILD_DATE=$(BUILD_DATE)"'
default: build
build:
go build -ldflags $(LD_FLAGS) -gcflags "-N" -i -o $(SERVER_DEMO_BIN) $(SERVER_DEMO_PATH)/main.go
go build -ldflags $(LD_FLAGS) -gcflags "-N" -i -o $(CLIENT_DEMO_BIN) $(CLIENT_DEMO_PATH)/main.go
clean:
rm $(SERVER_DEMO_BIN)
rm $(CLIENT_DEMO_BIN)

8
utils/globalobj.go

@ -92,6 +92,10 @@ func (g *GlobalObj) Reload() {
提供init方法默认加载 提供init方法默认加载
*/ */
func init() { func init() {
pwd, err := os.Getwd()
if err != nil {
pwd = "."
}
//初始化GlobalObject变量,设置一些默认值 //初始化GlobalObject变量,设置一些默认值
GlobalObject = &GlobalObj{ GlobalObject = &GlobalObj{
Name: "ZinxServerApp", Name: "ZinxServerApp",
@ -100,11 +104,11 @@ func init() {
Host: "0.0.0.0", Host: "0.0.0.0",
MaxConn: 12000, MaxConn: 12000,
MaxPacketSize: 4096, MaxPacketSize: 4096,
ConfFilePath: "conf/zinx.json",
ConfFilePath: pwd+"/conf/zinx.json",
WorkerPoolSize: 10, WorkerPoolSize: 10,
MaxWorkerTaskLen: 1024, MaxWorkerTaskLen: 1024,
MaxMsgChanLen: 1024, MaxMsgChanLen: 1024,
LogDir: "./log",
LogDir: pwd+"/log",
LogFile: "", LogFile: "",
LogDebugClose: false, LogDebugClose: false,
} }

9
znet/server.go

@ -44,6 +44,7 @@ type Server struct {
创建一个服务器句柄 创建一个服务器句柄
*/ */
func NewServer() ziface.IServer { func NewServer() ziface.IServer {
printLogo()
s := &Server{ s := &Server{
Name: utils.GlobalObject.Name, Name: utils.GlobalObject.Name,
@ -168,14 +169,18 @@ func (s *Server) CallOnConnStop(conn ziface.IConnection) {
} }
} }
func init() {
func printLogo() {
fmt.Println(zinxLogo) fmt.Println(zinxLogo)
fmt.Println(topLine) fmt.Println(topLine)
fmt.Println(fmt.Sprintf("%s [Github] https://github.com/aceld %s", borderLine, borderLine)) fmt.Println(fmt.Sprintf("%s [Github] https://github.com/aceld %s", borderLine, borderLine))
fmt.Println(fmt.Sprintf("%s [tutorial] https://www.jianshu.com/p/23d07c0a28e5 %s", borderLine, borderLine))
fmt.Println(fmt.Sprintf("%s [tutorial] https://www.kancloud.cn/aceld/zinx %s", borderLine, borderLine))
fmt.Println(bottomLine) fmt.Println(bottomLine)
fmt.Printf("[Zinx] Version: %s, MaxConn: %d, MaxPacketSize: %d\n", fmt.Printf("[Zinx] Version: %s, MaxConn: %d, MaxPacketSize: %d\n",
utils.GlobalObject.Version, utils.GlobalObject.Version,
utils.GlobalObject.MaxConn, utils.GlobalObject.MaxConn,
utils.GlobalObject.MaxPacketSize) utils.GlobalObject.MaxPacketSize)
} }
func init() {
}

7
ztimer/timerscheduler_test.go

@ -65,15 +65,14 @@ func TestNewAutoExecTimerScheduler(t *testing.T) {
select {} select {}
} }
//测试取消一个定时器 //测试取消一个定时器
func TestCancelTimerScheduler(t *testing.T) { func TestCancelTimerScheduler(t *testing.T) {
Scheduler := NewAutoExecTimerScheduler() Scheduler := NewAutoExecTimerScheduler()
f1 := NewDelayFunc(foo, []interface{}{3, 3}) f1 := NewDelayFunc(foo, []interface{}{3, 3})
f2 := NewDelayFunc(foo, []interface{}{5, 5}) f2 := NewDelayFunc(foo, []interface{}{5, 5})
timerId1,_:=Scheduler.CreateTimerAfter(f1, time.Duration(3)*time.Second)
timerId2,_:=Scheduler.CreateTimerAfter(f2, time.Duration(5)*time.Second)
log.Printf("timerId1=%d ,timerId2=%d\n",timerId1,timerId2)
timerId1, _ := Scheduler.CreateTimerAfter(f1, time.Duration(3)*time.Second)
timerId2, _ := Scheduler.CreateTimerAfter(f2, time.Duration(5)*time.Second)
log.Printf("timerId1=%d ,timerId2=%d\n", timerId1, timerId2)
Scheduler.CancelTimer(timerId1) //删除timerId1 Scheduler.CancelTimer(timerId1) //删除timerId1
//阻塞等待 //阻塞等待

Loading…
Cancel
Save