警告
本文最后更新于 2020-12-27,文中内容可能已过时。
Server脑图
首先创建两个模块使用,一个是 ziface
,一个是 znet
,分别创建 ziface/iserver.go
和 znet/server.go
作为接口,我们对外只提供方法,故抽象出三个方法,分别是:
iserver.go
:
1
2
3
4
5
6
7
8
9
|
// IServer 定义Server抽象层
type IServer interface {
// 启动
Start()
// 结束
Stop()
// 运行
Serve()
}
|
在server.go中定义Server结构体实现三个属性
- 服务器名
- 服务器IP
- 服务器监听端口
- IP版本(IPv4、IPv6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// Server 包含一个服务必要的属性
type Server struct {
Name string
IPVersion string
IP string
Port int
}
// NewServer 实例Server
func NewServer(name string) ziface.IServer {
return &Server{
Name: name,
IPVersion: "tcp4",
IP: "0.0.0.0",
Port: 8999,
}
}
|
接下来去实现IServer中所有方法
启动一个服务器需要分为三步:
- 获取TCP的地址
- 监听服务器地址
- 启动Server网络连接业务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
// Start ...
func (s *Server) Start() {
fmt.Printf("[Start] Server Listener 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 {
log.Println("resolve tcp addr error: ", err)
return
}
// 2. 监听服务器的地址
listener, err := net.ListenTCP(s.IPVersion, addr)
if err != nil {
log.Println("listen ", s.IPVersion, "error ", err)
return
}
log.Println("Start Zinx server success, ", s.Name, "Listening...")
// 3. 阻塞等待服务器链接,处理客户端链接业务(读写)
for {
// 如果有客户端连接,阻塞会返回
conn, err := listener.AcceptTCP()
if err != nil {
log.Println("Accept error ", 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
}
//回显
if _, err := conn.Write(buf[:cnt]); err !=nil {
fmt.Println("write back buf err ", err)
continue
}
}
}()
}
}()
}
|
1
2
3
4
|
// Stop ...
func (s *Server) Stop() {
log.Println("[STOP] Zinx server , name ", s.Name)
}
|
1
2
3
4
5
6
7
8
9
10
|
// Serve ...
func (s *Server) Serve() {
// 启动服务
s.Start()
// todo 用来再此处处理其他业务
// 阻塞在此,防止主协程结束
select {}
}
|
在项目中创建 v1/client.go
和 v1/server.go
代码分别如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
// client.go
package main
import (
"log"
"net"
"time"
)
func main() {
log.Println("client start...")
time.Sleep(1 * time.Second)
// 1. 直接链接远程服务器,得到一个conn链接
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
log.Println("client start error ", err)
return
}
// 2. 链接调用write写数据
for {
_, err := conn.Write([]byte("Hello Zinx v1"))
if err != nil {
log.Println("write buf error ", err)
return
}
buf := make([]byte, 512)
cnt, err := conn.Read(buf)
if err != nil {
log.Println("read buf error ", err)
return
}
log.Printf("Server call back %s, cnt = %d\n", buf, cnt)
// CPU阻塞
time.Sleep(1 * time.Second)
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
// server.go
package main
import "Zinx/znet"
func main() {
server := znet.NewServer("Zinx v1")
server.Serve()
}
|
在控制台分别运行server.go 和 client.go 可以看到client一直在发送,server也可以接收。