#### 9.5 使用Zinx-V0.9完成应用程序
好了,现在我们基本上已经将全部的连接管理的功能集成到Zinx中了,接下来就需要测试一下链接管理模块是否可以使用了。
写一个服务端:
> Server.go
```go
package main
import (
"fmt"
"zinx/ziface"
"zinx/znet"
)
//ping test 自定义路由
type PingRouter struct {
znet.BaseRouter
}
//Ping Handle
func (this *PingRouter) Handle(request ziface.IRequest) {
fmt.Println("Call PingRouter Handle")
//先读取客户端的数据,再回写ping...ping...ping
fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
if err != nil {
fmt.Println(err)
}
}
type HelloZinxRouter struct {
znet.BaseRouter
}
//HelloZinxRouter Handle
func (this *HelloZinxRouter) Handle(request ziface.IRequest) {
fmt.Println("Call HelloZinxRouter Handle")
//先读取客户端的数据,再回写ping...ping...ping
fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
err := request.GetConnection().SendBuffMsg(1, []byte("Hello Zinx Router V0.8"))
if err != nil {
fmt.Println(err)
}
}
//创建连接的时候执行
func DoConnectionBegin(conn ziface.IConnection) {
fmt.Println("DoConnecionBegin is Called ... ")
err := conn.SendMsg(2, []byte("DoConnection BEGIN..."))
if err != nil {
fmt.Println(err)
}
}
//连接断开的时候执行
func DoConnectionLost(conn ziface.IConnection) {
fmt.Println("DoConneciotnLost is Called ... ")
}
func main() {
//创建一个server句柄
s := znet.NewServer()
//注册链接hook回调函数
s.SetOnConnStart(DoConnectionBegin)
s.SetOnConnStop(DoConnectionLost)
//配置路由
s.AddRouter(0, &PingRouter{})
s.AddRouter(1, &HelloZinxRouter{})
//开启服务
s.Serve()
}
```
我们这里注册了两个Hook函数一个是链接初始化之后`DoConnectionBegin()`和链接停止之前`DoConnectionLost()`。
`DoConnectionBegin()`会发给客户端一个消息2的文本,并且在服务端打印一个调试信息"DoConnecionBegin is Called ... "
`DoConnectionLost()`在服务端打印一个调试信息"DoConneciotnLost is Called ... "
客户端:
> Client.go
```go
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 {
//发封包message消息
dp := znet.NewDataPack()
msg, _ := dp.Pack(znet.NewMsgPackage(0,[]byte("Zinx V0.8 Client0 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)
}
}
```
代码不变。
启动服务端
```
$go run Server.go
```
启动客户端
```
$go run Client.go
```
服务端结果:
```bash
$ go run Server.go
Add api msgId = 0
Add api msgId = 1
[START] Server name: zinx v-0.8 demoApp,listenner at IP: 127.0.0.1, Port 7777 is starting
[Zinx] Version: V0.4, MaxConn: 3, MaxPacketSize: 4096
start Zinx server zinx v-0.8 demoApp succ, now listenning...
Worker ID = 9 is started.
Worker ID = 5 is started.
Worker ID = 6 is started.
Worker ID = 7 is started.
Worker ID = 8 is started.
Worker ID = 1 is started.
Worker ID = 0 is started.
Worker ID = 2 is started.
Worker ID = 3 is started.
Worker ID = 4 is started.
connection add to ConnManager successfully: conn num = 1
---> CallOnConnStart....
DoConnecionBegin is Called ...
[Writer Goroutine is running]
[Reader Goroutine is running]
Add ConnID= 0 request msgID= 0 to workerID= 0
Call PingRouter Handle
recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
Add ConnID= 0 request msgID= 0 to workerID= 0
Call PingRouter Handle
recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
Add ConnID= 0 request msgID= 0 to workerID= 0
Call PingRouter Handle
recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
Add ConnID= 0 request msgID= 0 to workerID= 0
Call PingRouter Handle
recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
Add ConnID= 0 request msgID= 0 to workerID= 0
Call PingRouter Handle
recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
read msg head error read tcp4 127.0.0.1:7777->127.0.0.1:49510: read: connection reset by peer
Conn Stop()...ConnID = 0
---> CallOnConnStop....
DoConneciotnLost is Called ...
connection Remove ConnID= 0 successfully: conn num = 0
127.0.0.1:49510 [conn Reader exit!]
127.0.0.1:49510 [conn Writer exit!]
```
客户端结果:
```bash
$ go run Client0.go
Client Test ... start
==> Recv Msg: ID= 2 , len= 21 , data= DoConnection BEGIN...
==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
^Csignal: interrupt
```
客户端创建成功,回调Hook已经执行,并且Conn被添加到ConnManager 中, conn num = 1,
当我们手动CTRL+C 关闭客户端的时候, 服务器ConnManager已经成功将Conn摘掉,conn num = 0.
同时服务端也打印出 conn停止之后的回调信息。
- 一、引言
- 1、写在前面
- 2、初探Zinx架构
- 二、初识Zinx框架
- 1. Zinx-V0.1-基础Server
- 2.Zinx-V0.2-简单的连接封装与业务绑定
- 三、Zinx框架基础路由模块
- 3.1 IRequest 消息请求抽象类
- 3.2 IRouter 路由配置抽象类
- 3.3 Zinx-V0.3-集成简单路由功能
- 3.4 Zinx-V0.3代码实现
- 3.5 使用Zinx-V0.3完成应用程序
- 四、Zinx的全局配置
- 4.1 Zinx-V0.4增添全局配置代码实现
- 4.2 使用Zinx-V0.4完成应用程序
- 五、Zinx的消息封装
- 5.1 创建消息封装类型
- 5.2 消息的封包与拆包
- 5.3 Zinx-V0.5代码实现
- 5.4 使用Zinx-V0.5完成应用程序
- 六、Zinx的多路由模式
- 6.1 创建消息管理模块
- 6.2 Zinx-V0.6代码实现
- 6.3 使用Zinx-V0.6完成应用程序
- 七、Zinx的读写分离模型
- 7.1 Zinx-V0.7代码实现
- 7.2 使用Zinx-V0.7完成应用程序
- 八、Zinx的消息队列及多任务机制
- 8.1 创建消息队列
- 8.2 创建及启动Worker工作池
- 8.3 发送消息给消息队列
- 8.4 Zinx-V0.8代码实现
- 8.5 使用Zinx-V0.8完成应用程序
- 九、Zinx的链接管理
- 9.1 创建链接管理模块
- 9.2 链接管理模块集成到Zinx中
- 9.3 链接的带缓冲的发包方法
- 9.4 注册链接启动/停止自定义Hook方法功能
- 9.5 使用Zinx-V0.9完成应用程序
- 十、Zinx的连接属性设置
- 10.1 给链接添加链接配置接口
- 10.2 链接属性方法实现
- 10.3 链接属性Zinx-V0.10单元测试
- 基于Zinx的应用案例
- 一、应用案例介绍
- 二、服务器应用基础协议
- 三、MMO多人在线游戏AOI算法
- 3.1 网络法实现AOI算法
- 3.2 实现AOI格子结构
- 3.3 实现AOI管理模块
- 3.4 求出九宫格
- 3.5 AOI格子添加删除操作
- 3.6 AOI模块单元测试
- 四、数据传输协议protocol buffer
- 4.1 简介
- 4.2 数据交换格式
- 4.3 protobuf环境安装
- 4.4 protobuf语法
- 4.5 编译protobuf
- 4.6 利用protobuf生成的类来编码
- 五、MMO游戏的Proto3协议
- 六、构建项目与用户上线
- 6.1 构建项目
- 6.2用户上线流程
- 七、世界聊天系统实现
- 7.1 世界管理模块
- 7.2 世界聊天系统实现
- 八、上线位置信息同步
- 九、移动位置与AOI广播(未跨越格子)
- 十、玩家下线
- 十一、移动与AOI广播(跨越格子)