• 9.5 使用Zinx-V0.9完成应用程序

    9.5 使用Zinx-V0.9完成应用程序

    好了,现在我们基本上已经将全部的连接管理的功能集成到Zinx中了,接下来就需要测试一下链接管理模块是否可以使用了。

    写一个服务端:

    Server.go

    1. package main
    2. import (
    3. "fmt"
    4. "zinx/ziface"
    5. "zinx/znet"
    6. )
    7. //ping test 自定义路由
    8. type PingRouter struct {
    9. znet.BaseRouter
    10. }
    11. //Ping Handle
    12. func (this *PingRouter) Handle(request ziface.IRequest) {
    13. fmt.Println("Call PingRouter Handle")
    14. //先读取客户端的数据,再回写ping...ping...ping
    15. fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
    16. err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
    17. if err != nil {
    18. fmt.Println(err)
    19. }
    20. }
    21. type HelloZinxRouter struct {
    22. znet.BaseRouter
    23. }
    24. //HelloZinxRouter Handle
    25. func (this *HelloZinxRouter) Handle(request ziface.IRequest) {
    26. fmt.Println("Call HelloZinxRouter Handle")
    27. //先读取客户端的数据,再回写ping...ping...ping
    28. fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
    29. err := request.GetConnection().SendBuffMsg(1, []byte("Hello Zinx Router V0.8"))
    30. if err != nil {
    31. fmt.Println(err)
    32. }
    33. }
    34. //创建连接的时候执行
    35. func DoConnectionBegin(conn ziface.IConnection) {
    36. fmt.Println("DoConnecionBegin is Called ... ")
    37. err := conn.SendMsg(2, []byte("DoConnection BEGIN..."))
    38. if err != nil {
    39. fmt.Println(err)
    40. }
    41. }
    42. //连接断开的时候执行
    43. func DoConnectionLost(conn ziface.IConnection) {
    44. fmt.Println("DoConneciotnLost is Called ... ")
    45. }
    46. func main() {
    47. //创建一个server句柄
    48. s := znet.NewServer()
    49. //注册链接hook回调函数
    50. s.SetOnConnStart(DoConnectionBegin)
    51. s.SetOnConnStop(DoConnectionLost)
    52. //配置路由
    53. s.AddRouter(0, &PingRouter{})
    54. s.AddRouter(1, &HelloZinxRouter{})
    55. //开启服务
    56. s.Serve()
    57. }

    我们这里注册了两个Hook函数一个是链接初始化之后DoConnectionBegin()和链接停止之前DoConnectionLost()

    DoConnectionBegin()会发给客户端一个消息2的文本,并且在服务端打印一个调试信息"DoConnecionBegin is Called … "

    DoConnectionLost()在服务端打印一个调试信息"DoConneciotnLost is Called … "

    客户端:

    Client.go

    1. package main
    2. import (
    3. "fmt"
    4. "io"
    5. "net"
    6. "time"
    7. "zinx/znet"
    8. )
    9. /*
    10. 模拟客户端
    11. */
    12. func main() {
    13. fmt.Println("Client Test ... start")
    14. //3秒之后发起测试请求,给服务端开启服务的机会
    15. time.Sleep(3 * time.Second)
    16. conn,err := net.Dial("tcp", "127.0.0.1:7777")
    17. if err != nil {
    18. fmt.Println("client start err, exit!")
    19. return
    20. }
    21. for {
    22. //发封包message消息
    23. dp := znet.NewDataPack()
    24. msg, _ := dp.Pack(znet.NewMsgPackage(0,[]byte("Zinx V0.8 Client0 Test Message")))
    25. _, err := conn.Write(msg)
    26. if err !=nil {
    27. fmt.Println("write error err ", err)
    28. return
    29. }
    30. //先读出流中的head部分
    31. headData := make([]byte, dp.GetHeadLen())
    32. _, err = io.ReadFull(conn, headData) //ReadFull 会把msg填充满为止
    33. if err != nil {
    34. fmt.Println("read head error")
    35. break
    36. }
    37. //将headData字节流 拆包到msg中
    38. msgHead, err := dp.Unpack(headData)
    39. if err != nil {
    40. fmt.Println("server unpack err:", err)
    41. return
    42. }
    43. if msgHead.GetDataLen() > 0 {
    44. //msg 是有data数据的,需要再次读取data数据
    45. msg := msgHead.(*znet.Message)
    46. msg.Data = make([]byte, msg.GetDataLen())
    47. //根据dataLen从io中读取字节流
    48. _, err := io.ReadFull(conn, msg.Data)
    49. if err != nil {
    50. fmt.Println("server unpack data err:", err)
    51. return
    52. }
    53. fmt.Println("==> Recv Msg: ID=", msg.Id, ", len=", msg.DataLen, ", data=", string(msg.Data))
    54. }
    55. time.Sleep(1*time.Second)
    56. }
    57. }

    代码不变。

    启动服务端

    1. $go run Server.go

    启动客户端

    1. $go run Client.go

    服务端结果:

    1. $ go run Server.go
    2. Add api msgId = 0
    3. Add api msgId = 1
    4. [START] Server name: zinx v-0.8 demoApp,listenner at IP: 127.0.0.1, Port 7777 is starting
    5. [Zinx] Version: V0.4, MaxConn: 3, MaxPacketSize: 4096
    6. start Zinx server zinx v-0.8 demoApp succ, now listenning...
    7. Worker ID = 9 is started.
    8. Worker ID = 5 is started.
    9. Worker ID = 6 is started.
    10. Worker ID = 7 is started.
    11. Worker ID = 8 is started.
    12. Worker ID = 1 is started.
    13. Worker ID = 0 is started.
    14. Worker ID = 2 is started.
    15. Worker ID = 3 is started.
    16. Worker ID = 4 is started.
    17. connection add to ConnManager successfully: conn num = 1
    18. ---> CallOnConnStart....
    19. DoConnecionBegin is Called ...
    20. [Writer Goroutine is running]
    21. [Reader Goroutine is running]
    22. Add ConnID= 0 request msgID= 0 to workerID= 0
    23. Call PingRouter Handle
    24. recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    25. Add ConnID= 0 request msgID= 0 to workerID= 0
    26. Call PingRouter Handle
    27. recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    28. Add ConnID= 0 request msgID= 0 to workerID= 0
    29. Call PingRouter Handle
    30. recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    31. Add ConnID= 0 request msgID= 0 to workerID= 0
    32. Call PingRouter Handle
    33. recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    34. Add ConnID= 0 request msgID= 0 to workerID= 0
    35. Call PingRouter Handle
    36. recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    37. read msg head error read tcp4 127.0.0.1:7777->127.0.0.1:49510: read: connection reset by peer
    38. Conn Stop()...ConnID = 0
    39. ---> CallOnConnStop....
    40. DoConneciotnLost is Called ...
    41. connection Remove ConnID= 0 successfully: conn num = 0
    42. 127.0.0.1:49510 [conn Reader exit!]
    43. 127.0.0.1:49510 [conn Writer exit!]

    客户端结果:

    1. $ go run Client0.go
    2. Client Test ... start
    3. ==> Recv Msg: ID= 2 , len= 21 , data= DoConnection BEGIN...
    4. ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    5. ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    6. ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    7. ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    8. ^Csignal: interrupt

    客户端创建成功,回调Hook已经执行,并且Conn被添加到ConnManager 中, conn num = 1,

    当我们手动CTRL+C 关闭客户端的时候, 服务器ConnManager已经成功将Conn摘掉,conn num = 0.

    同时服务端也打印出 conn停止之后的回调信息。