Golang Go语言如何远程调试代码?

发布于 1周前 作者 gougou168 来自 Go语言

Golang Go语言如何远程调试代码?

博客地址: https://www.douyacun.com

原文链接: https://www.douyacun.com/article/65021b4fee1f73b55ba77b46bb18b3a7

问题: epoll 这只能运行在 linux,有问题没发调试,蛋疼吗?

首先想到装个 docker,运行个 centos,然后对着 docker 又是一顿撸。还是没发调试,

gdb 也是可以调试 go 程序的,问题是,这 tm 一个项目几百个文件都有了,我 gdb 怎么断点啊,大概的思路就是从函数调用的地方开始入手,这啥时候是个头啊,简单的还行,果断放弃了

delve dlv 其实很不错的,也能像 gdb 一样支持,对 goroutine 支持也很完美,问题来了,docker 运行的 centos,我就是装个 dlv, go get -u github.com/go-delve/delve/cmd/dlv 装不动,只能心里默默诅咒那个下决定对 github 限速的人。google 我能理解,但是 github 这个真理解不了。只能走代理了。关于[怎么在 centos 上使用代理](/linux/centos 使用 ss 代理.md)

goland 配置

Run/Edit configurations

host 配置

docker 运行的 centos,创建 container 的时候,指定 -p 2345:2345 , 把容器的端口映射到宿主机器上就 ok 了

编译调试

goland 里面介绍的很明白,有一个坑 exec ./main的时候后面怎么传参数给调试进程,正确的姿势: 后面跟 --,告诉 dlv,这是给调试进程用的。

dlv --listen=:9004 --headless=true --api-version=2 --accept-multiclient exec ./main -- start --env debug

dlv listen 以后怎么退出来?

不好意思,我也没有找到正确的姿势,万能的方式,新启动一个终端 kill 掉他,然后会问,docker 怎么 attach 以后还是当前窗口,这个....

docker exec -it centos7 bash

看一下我调试解决的 bug

func start() {
	for {
		clients, err := hub.Wait()
		if err != nil {
			logger.Debugf("epoll wait %v", err)
			continue
		}
		for _, client := range clients {
      // 这里是 68 行,下面这一行会报 空指针 的错误
			bt, opCode, err := wsutil.ReadClientData(client.conn)
			if err != nil {
				log.Printf("read message error: %v", err)
				continue
			}
			// 处理 ping/pong/close
			if opCode.IsControl() {
				err := wsutil.HandleClientControlMessage(client.conn, wsutil.Message{
					OpCode:  opCode,
					Payload: bt,
				})
				if err != nil {
					if _, ok := err.(wsutil.ClosedError); ok {
						hub.unregister <- *client
					}
					continue
				}
				continue
			}
			cmsg := ClientMessage{}
			if err := json.Unmarshal(bt, cmsg); err != nil {
				logger.Errorf("json unmarshal error: %v", err)
				continue
			}
			hub.broadcast <- NewDefaultMsg(client, cmsg.Content, cmsg.ChannelId)
		}
	}
}

报错信息:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0xdf08d4]

goroutine 20 [running]: dyc/internal/module/chat.start() /root/github/api.douyacun.com/internal/module/chat/client.go:68 +0x64 created by dyc/internal/module/chat.init.0 /root/github/api.douyacun.com/internal/module/chat/client.go:26 +0x82

可以看出来是 client 为 nil 了,那就出现hub.Wait(), 调用 epoll wait 的时候返回的 client 有 nil,debug 一下

wait 函数的代码:

func (e *epoll) Wait() ([]*Client, error) {
	events := make([]syscall.EpollEvent, 100)
	n, err := syscall.EpollWait(e.Fd, events, 100)
	if err != nil {
		return nil, err
	}
	connections := make([]*Client, n)
	for i := 0; i < n; i++ {
		conn := e.connections[int(events[i].Fd)]
		connections = append(connections, conn)
	}
	return connections, nil
}

next 一直运行,看一下有连接进来的情况:

这里应该是对syscall.EpollWait 第二个参数 events, 第一个返回值 n 的理解有问题,但这不是关键,关键是远程调试姿势有了。


更多关于Golang Go语言如何远程调试代码?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

go get 用 GOPROXY 不行嘛

更多关于Golang Go语言如何远程调试代码?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html



go get 可以用 GOPROXY

不过这是在本地调试 linux 上的代码,因为用到了 epoll,mac 上无法执行的

在Golang(Go语言)中,远程调试代码可以通过几种方式实现,其中使用Delve调试器和远程调试配置是比较常见和有效的方法。以下是一个简要的步骤指南:

  1. 安装Delve: Delve是Go语言的官方调试器,支持本地和远程调试。你可以通过运行go get -u github.com/go-delve/delve/cmd/dlv来安装它。

  2. 编译你的程序: 在调试模式下编译你的Go程序,使用go build -gcflags "all=-N -l" main.go命令。这会生成一个未优化的二进制文件,包含所有调试信息。

  3. 启动远程调试服务器: 使用Delve启动远程调试服务器,命令如下:dlv --listen=:2345 --headless=true --api-version=2 exec ./your_program。这里2345是监听端口,你可以根据需要更改。

  4. 连接调试客户端: 你可以使用Delve CLI客户端或其他兼容的调试工具(如VSCode、GoLand等)连接到远程调试服务器。例如,使用VSCode时,配置launch.json文件,指定远程调试服务器的地址和端口。

  5. 开始调试: 一旦连接成功,你就可以像本地调试一样设置断点、查看变量、单步执行等。

确保你的开发环境和远程环境之间的网络连接是通畅的,并且防火墙或安全组规则允许相应的端口通信。通过以上步骤,你应该能够成功地在Go语言中实现远程代码调试。

回到顶部