# 5.5 调试客户端

# 5.5.1 基础介绍

调试客户端作为日常开发调试的一种重要工具,为游戏开发者提供了非常便捷的接口方案。开发者可以借助flag (opens new window)包来接收不同的输入参数从而控制不同的客户端行为。同时,框架提供的调试客户端也具备非常出色的性能,也可以作为压测客户端来使用。

# 5.5.2 TCP客户端示例

以下完整示例详见:client-tcp-example (opens new window)

  1. 创建项目
$ mkdir client-tcp-example
1
  1. 安装依赖
$ cd client-tcp-example
$ go mod init client-tcp-example
$ go get github.com/dobyte/due/v2@v2.4.2
$ go get github.com/dobyte/due/network/tcp/v2@e5cd009
1
2
3
4
  1. 启动配置

文件位置:client-tcp-example/etc/etc.toml (opens new window)

# 进程号
pid = "./run/due.pid"
# 开发模式。支持模式:debug、test、release(设置优先级:配置文件 < 环境变量 < 运行参数 < mode.SetMode())
mode = "debug"
# 统一时区设置。项目中的时间获取请使用xtime.Now()
timezone = "Local"
# 容器关闭最大等待时间。支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为0
shutdownMaxWaitTime = "0s"

[cluster.client]
    # 实例ID,集群中唯一。不填写默认自动生成唯一的实例ID
    id = ""
    # 实例名称
    name = "client"
    # 编解码器。可选:json | proto。默认为proto
    codec = "json"

[network.tcp.client]
    # 拨号地址
    addr = "127.0.0.1:3553"
    # 拨号超时时间,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为5s
    timeout = "5s"
    # CA证书文件
    caFile = ""
    # 证书域名
    serverName = ""
    # 心跳间隔时间;设置为0则不启用心跳检测,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为10s
    heartbeatInterval = "10s"

[packet]
    # 字节序,默认为big。可选:little | big
    byteOrder = "big"
    # 路由字节数,默认为2字节
    routeBytes = 2
    # 序列号字节数,默认为2字节
    seqBytes = 2
    # 消息字节数,默认为5000字节
    bufferBytes = 5000
    # 是否携带服务器心跳时间
    heartbeatTime = false
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
  1. 编写示例

文件位置:client-tcp-example/main.go (opens new window)

package main

import (
	"fmt"
	"time"

	"github.com/dobyte/due/network/tcp/v2"
	"github.com/dobyte/due/v2"
	"github.com/dobyte/due/v2/cluster"
	"github.com/dobyte/due/v2/cluster/client"
	"github.com/dobyte/due/v2/log"
	"github.com/dobyte/due/v2/utils/xtime"
)

// 路由号
const greet = 1

func main() {
	// 创建容器
	container := due.NewContainer()
	// 创建客户端组件
	component := client.NewClient(
		client.WithClient(tcp.NewClient()),
	)
	// 初始化监听
	initApp(component.Proxy())
	// 添加客户端组件
	container.Add(component)
	// 启动容器
	container.Serve()
}

// 初始化应用
func initApp(proxy *client.Proxy) {
	// 监听组件启动
	proxy.AddHookListener(cluster.Start, startHandler)
	// 监听连接建立
	proxy.AddEventListener(cluster.Connect, connectHandler)
	// 监听消息回复
	proxy.AddRouteHandler(greet, greetHandler)
}

// 组件启动处理器
func startHandler(proxy *client.Proxy) {
	if _, err := proxy.Dial(); err != nil {
		log.Errorf("connect server failed: %v", err)
		return
	}
}

// 连接建立处理器
func connectHandler(conn *client.Conn) {
	doPushMessage(conn)
}

// 消息回复处理器
func greetHandler(ctx *client.Context) {
	res := &greetRes{}

	if err := ctx.Parse(res); err != nil {
		log.Errorf("invalid response message, err: %v", err)
		return
	}

	if res.Code != 0 {
		log.Errorf("node response failed, code: %d", res.Code)
		return
	}

	log.Info(res.Message)

	time.AfterFunc(time.Second, func() {
		doPushMessage(ctx.Conn())
	})
}

// 请求
type greetReq struct {
	Message string `json:"message"`
}

// 响应
type greetRes struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// 推送消息
func doPushMessage(conn *client.Conn) {
	if err := conn.Push(&cluster.Message{
		Route: 1,
		Data: &greetReq{
			Message: fmt.Sprintf("I'm client, and the current time is: %s", xtime.Now().Format(xtime.DateTime)),
		},
	}); err != nil {
		log.Errorf("push message failed: %v", err)
	}
}
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  1. 启动服务
$ cd client-tcp-example
$ go run main.go
                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.4.2                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 8864                                            |
| Mode: debug                                          |
| Time: 2025-10-25 10:46:23.4062229 +0800 CST          |
└──────────────────────────────────────────────────────┘
┌────────────────────────Client────────────────────────┐
| Name: client                                         |
| Codec: json                                          |
| Protocol: tcp                                        |
| Encryptor: -                                         |
└──────────────────────────────────────────────────────┘
INFO[2025/10/25 10:46:23.410469] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:46:23
INFO[2025/10/25 10:46:24.413036] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:46:24
INFO[2025/10/25 10:46:25.423296] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:46:25
INFO[2025/10/25 10:46:26.424702] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:46:26
INFO[2025/10/25 10:46:27.426387] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:46:27
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

# 3.5.3 WS客户端示例

以下完整示例详见:client-ws-example (opens new window)

  1. 创建项目
$ mkdir client-ws-example
1
  1. 安装依赖
$ cd client-ws-example
$ go mod init client-ws-example
$ go get github.com/dobyte/due/v2@v2.4.2
$ go get github.com/dobyte/due/network/ws/v2@e5cd009
1
2
3
4
  1. 启动配置

文件位置:client-ws-example/etc/etc.toml (opens new window)

# 进程号
pid = "./run/due.pid"
# 开发模式。支持模式:debug、test、release(设置优先级:配置文件 < 环境变量 < 运行参数 < mode.SetMode())
mode = "debug"
# 统一时区设置。项目中的时间获取请使用xtime.Now()
timezone = "Local"
# 容器关闭最大等待时间。支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为0
shutdownMaxWaitTime = "0s"

[cluster.client]
    # 实例ID,集群中唯一。不填写默认自动生成唯一的实例ID
    id = ""
    # 实例名称
    name = "client"
    # 编解码器。可选:json | proto。默认为proto
    codec = "json"

[network.ws.client]
    # 拨号地址
    url = "ws://127.0.0.1:3553"
    # 握手超时时间,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为10s
    handshakeTimeout = "10s"
    # 心跳间隔时间;设置为0则不启用心跳检测,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为10s
    heartbeatInterval = "10s"

[packet]
    # 字节序,默认为big。可选:little | big
    byteOrder = "big"
    # 路由字节数,默认为2字节
    routeBytes = 2
    # 序列号字节数,默认为2字节
    seqBytes = 2
    # 消息字节数,默认为5000字节
    bufferBytes = 5000
    # 是否携带服务器心跳时间
    heartbeatTime = false
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
  1. 编写示例

文件位置:client-ws-example/main.go (opens new window)

package main

import (
	"fmt"
	"time"

	"github.com/dobyte/due/network/ws/v2"
	"github.com/dobyte/due/v2"
	"github.com/dobyte/due/v2/cluster"
	"github.com/dobyte/due/v2/cluster/client"
	"github.com/dobyte/due/v2/log"
	"github.com/dobyte/due/v2/utils/xtime"
)

// 路由号
const greet = 1

func main() {
	// 创建容器
	container := due.NewContainer()
	// 创建客户端组件
	component := client.NewClient(
		client.WithClient(ws.NewClient()),
	)
	// 初始化监听
	initApp(component.Proxy())
	// 添加客户端组件
	container.Add(component)
	// 启动容器
	container.Serve()
}

// 初始化应用
func initApp(proxy *client.Proxy) {
	// 监听组件启动
	proxy.AddHookListener(cluster.Start, startHandler)
	// 监听连接建立
	proxy.AddEventListener(cluster.Connect, connectHandler)
	// 监听消息回复
	proxy.AddRouteHandler(greet, greetHandler)
}

// 组件启动处理器
func startHandler(proxy *client.Proxy) {
	if _, err := proxy.Dial(); err != nil {
		log.Errorf("connect server failed: %v", err)
		return
	}
}

// 连接建立处理器
func connectHandler(conn *client.Conn) {
	doPushMessage(conn)
}

// 消息回复处理器
func greetHandler(ctx *client.Context) {
	res := &greetRes{}

	if err := ctx.Parse(res); err != nil {
		log.Errorf("invalid response message, err: %v", err)
		return
	}

	if res.Code != 0 {
		log.Errorf("node response failed, code: %d", res.Code)
		return
	}

	log.Info(res.Message)

	time.AfterFunc(time.Second, func() {
		doPushMessage(ctx.Conn())
	})
}

// 请求
type greetReq struct {
	Message string `json:"message"`
}

// 响应
type greetRes struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// 推送消息
func doPushMessage(conn *client.Conn) {
	if err := conn.Push(&cluster.Message{
		Route: 1,
		Data: &greetReq{
			Message: fmt.Sprintf("I'm client, and the current time is: %s", xtime.Now().Format(xtime.DateTime)),
		},
	}); err != nil {
		log.Errorf("push message failed: %v", err)
	}
}
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  1. 启动服务
$ cd client-ws-example
$ go run main.go
                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.4.2                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 20840                                           |
| Mode: debug                                          |
| Time: 2025-10-25 10:38:21.6446444 +0800 CST          |
└──────────────────────────────────────────────────────┘
┌────────────────────────Client────────────────────────┐
| Name: client                                         |
| Codec: json                                          |
| Protocol: ws                                         |
| Encryptor: -                                         |
└──────────────────────────────────────────────────────┘
INFO[2025/10/25 10:38:21.651187] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:38:21
INFO[2025/10/25 10:38:22.654799] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:38:22
INFO[2025/10/25 10:38:23.656016] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:38:23
INFO[2025/10/25 10:38:24.657855] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:38:24
INFO[2025/10/25 10:38:25.659807] main.go:70 I'm tcp server, and the current time is: 2025-10-25 10:38:25
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