1. Zinx-V0.1-基础Server

为了更好的看到Zinx框架,首先Zinx构建Zinx的最基本的两个模块zifaceznet

ziface主要是存放一些Zinx框架的全部模块的抽象层接口类,Zinx框架的最基本的是服务类接口iserver,定义在ziface模块中。

znet模块是zinx框架中网络相关功能的实现,所有网络相关模块都会定义在znet模块中。

1.1 Zinx-V0.1 代码实现

A) 创建zinx框架

在$GOPATH/src下创建zinx文件夹

B) 创建ziface、znet模块

在zinx/下 创建ziface、znet文件夹, 使当前的文件路径如下:

  1. └── zinx
  2. ├── ziface
  3. └──
  4. └── znet
  5. ├──
C) 在ziface下创建服务模块抽象层iserver.go

zinx/ziface/iserver.go

  1. package ziface
  2. //定义服务器接口
  3. type IServer interface{
  4. //启动服务器方法
  5. Start()
  6. //停止服务器方法
  7. Stop()
  8. //开启业务服务方法
  9. Serve()
  10. }
D) 在znet下实现服务模块server.go
  1. package znet
  2. import (
  3. "fmt"
  4. "net"
  5. "time"
  6. "zinx/ziface"
  7. )
  8. //iServer 接口实现,定义一个Server服务类
  9. type Server struct {
  10. //服务器的名称
  11. Name string
  12. //tcp4 or other
  13. IPVersion string
  14. //服务绑定的IP地址
  15. IP string
  16. //服务绑定的端口
  17. Port int
  18. }
  19. //============== 实现 ziface.IServer 里的全部接口方法 ========
  20. //开启网络服务
  21. func (s *Server) Start() {
  22. fmt.Printf("[START] Server listenner at IP: %s, Port %d, is starting\n", s.IP, s.Port)
  23. //开启一个go去做服务端Linster业务
  24. go func() {
  25. //1 获取一个TCP的Addr
  26. addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
  27. if err != nil {
  28. fmt.Println("resolve tcp addr err: ", err)
  29. return
  30. }
  31. //2 监听服务器地址
  32. listenner, err:= net.ListenTCP(s.IPVersion, addr)
  33. if err != nil {
  34. fmt.Println("listen", s.IPVersion, "err", err)
  35. return
  36. }
  37. //已经监听成功
  38. fmt.Println("start Zinx server ", s.Name, " succ, now listenning...")
  39. //3 启动server网络连接业务
  40. for {
  41. //3.1 阻塞等待客户端建立连接请求
  42. conn, err := listenner.AcceptTCP()
  43. if err != nil {
  44. fmt.Println("Accept err ", err)
  45. continue
  46. }
  47. //3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接
  48. //3.3 TODO Server.Start() 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的
  49. //我们这里暂时做一个最大512字节的回显服务
  50. go func () {
  51. //不断的循环从客户端获取数据
  52. for {
  53. buf := make([]byte, 512)
  54. cnt, err := conn.Read(buf)
  55. if err != nil {
  56. fmt.Println("recv buf err ", err)
  57. continue
  58. }
  59. //回显
  60. if _, err := conn.Write(buf[:cnt]); err !=nil {
  61. fmt.Println("write back buf err ", err)
  62. continue
  63. }
  64. }
  65. }()
  66. }
  67. }()
  68. }
  69. func (s *Server) Stop() {
  70. fmt.Println("[STOP] Zinx server , name " , s.Name)
  71. //TODO Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
  72. }
  73. func (s *Server) Serve() {
  74. s.Start()
  75. //TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加
  76. //阻塞,否则主Go退出, listenner的go将会退出
  77. for {
  78. time.Sleep(10*time.Second)
  79. }
  80. }
  81. /*
  82. 创建一个服务器句柄
  83. */
  84. func NewServer (name string) ziface.IServer {
  85. s:= &Server {
  86. Name :name,
  87. IPVersion:"tcp4",
  88. IP:"0.0.0.0",
  89. Port:7777,
  90. }
  91. return s
  92. }

好了,以上我们已经完成了Zinx-V0.1的基本雏形了,虽然只是一个基本的回写客户端数据(我们之后会自定义处理客户端业务方法),那么接下来我们就应该测试我们当前的zinx-V0.1是否可以使用了。

1.2 Zinx框架单元测试样例

理论上我们应该可以现在导入zinx框架,然后写一个服务端程序,再写一个客户端程序进行测试,但是我们可以通过Go的单元Test功能,进行单元测试

创建zinx/znet/server_test.go

  1. package znet
  2. import (
  3. "fmt"
  4. "net"
  5. "testing"
  6. "time"
  7. )
  8. /*
  9. 模拟客户端
  10. */
  11. func ClientTest() {
  12. fmt.Println("Client Test ... start")
  13. //3秒之后发起测试请求,给服务端开启服务的机会
  14. time.Sleep(3 * time.Second)
  15. conn,err := net.Dial("tcp", "127.0.0.1:7777")
  16. if err != nil {
  17. fmt.Println("client start err, exit!")
  18. return
  19. }
  20. for {
  21. _, err := conn.Write([]byte("hello ZINX"))
  22. if err !=nil {
  23. fmt.Println("write error err ", err)
  24. return
  25. }
  26. buf :=make([]byte, 512)
  27. cnt, err := conn.Read(buf)
  28. if err != nil {
  29. fmt.Println("read buf error ")
  30. return
  31. }
  32. fmt.Printf(" server call back : %s, cnt = %d\n", buf, cnt)
  33. time.Sleep(1*time.Second)
  34. }
  35. }
  36. //Server 模块的测试函数
  37. func TestServer(t *testing.T) {
  38. /*
  39. 服务端测试
  40. */
  41. //1 创建一个server 句柄 s
  42. s := NewServer("[zinx V0.1]")
  43. /*
  44. 客户端测试
  45. */
  46. go ClientTest()
  47. //2 开启服务
  48. s.Serve()
  49. }

在zinx/znet下执行

  1. $ go test

执行结果,如下:

  1. [START] Server listenner at IP: 0.0.0.0, Port 7777, is starting
  2. Client Test ... start
  3. listen tcp4 err listen tcp4 0.0.0.0:7777: bind: address already in use
  4. server call back : hello ZINX, cnt = 6
  5. server call back : hello ZINX, cnt = 6
  6. server call back : hello ZINX, cnt = 6
  7. server call back : hello ZINX, cnt = 6

说明我们的zinx框架已经可以使用了。

1.3 使用Zinx-V0.1完成应用程序

当然,如果感觉go test 好麻烦,那么我们可以完全基于zinx写两个应用程序,Server.go , Client.go

Server.go

  1. package main
  2. import (
  3. "zinx/znet"
  4. )
  5. //Server 模块的测试函数
  6. func main() {
  7. //1 创建一个server 句柄 s
  8. s := znet.NewServer("[zinx V0.1]")
  9. //2 开启服务
  10. s.Serve()
  11. }

启动Server.go

  1. go run Server.go

Client.go

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "time"
  6. )
  7. func main() {
  8. fmt.Println("Client Test ... start")
  9. //3秒之后发起测试请求,给服务端开启服务的机会
  10. time.Sleep(3 * time.Second)
  11. conn,err := net.Dial("tcp", "127.0.0.1:7777")
  12. if err != nil {
  13. fmt.Println("client start err, exit!")
  14. return
  15. }
  16. for {
  17. _, err := conn.Write([]byte("hahaha"))
  18. if err !=nil {
  19. fmt.Println("write error err ", err)
  20. return
  21. }
  22. buf :=make([]byte, 512)
  23. cnt, err := conn.Read(buf)
  24. if err != nil {
  25. fmt.Println("read buf error ")
  26. return
  27. }
  28. fmt.Printf(" server call back : %s, cnt = %d\n", buf, cnt)
  29. time.Sleep(1*time.Second)
  30. }
  31. }

启动Client.go进行测试

  1. go run Client.go