[问题] Golang Go语言中调用 Linux 系统接口无法关闭 fd
[问题] Golang Go语言中调用 Linux 系统接口无法关闭 fd
项目中需要获取网卡的一些硬件信息,但遇到一点问题,现在用另一种方式解决了;但还是想搞懂为什么会报这个错误,基础太差,希望得到大佬的指导,非常感谢。
package main
import (
"fmt"
"golang.org/x/sys/unix"
"syscall"
"unsafe"
)
func main() {
for {
go func() {
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
defer func() {
if err := unix.Close(fd); err != nil {
fmt.Println("fd 关闭失败:", err)
}
}()
if err != nil {
fmt.Println(err)
return
}
var et struct {
Cmd uint32
Supported uint32
}
const GSET = 0x1
et.Cmd = GSET
var ifr struct {
Name [16]byte
Data uintptr
}
copy(ifr.Name[:], []byte("网卡名称"))
ifr.Data = uintptr(unsafe.Pointer(&et))
const SIOCETHTOOL = 0x8946
// 执行这一步后,fd 就无法关闭,close 返回 bad file descriptor
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), uintptr(unsafe.Pointer(&ifr)))
if errno != 0 {
fmt.Println(errno)
}
}()
}
select {}
}
更多关于[问题] Golang Go语言中调用 Linux 系统接口无法关闭 fd的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
另一种方法是不是直接执行个 sh 脚本获取返回值。
更多关于[问题] Golang Go语言中调用 Linux 系统接口无法关闭 fd的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
close 返回 EBADF 说明你要关闭的文件描述符是一个无效的文件描述符。你的代码有问题,关闭 fd 的 defer 应该放到错误处理的后面,因为如果 unix.Socket() 调用失败的话,fd 的值就是一个无效的文件描述符,你关闭它当然返回 EBADF
还有,现在都用 netlink
老铁,你把报错信息贴上来啊
查一下 syscall.SYS_IOCTL 的手册
跟 defer 放的位置无关;这个 fd 在被执行 ioctl 后才会关闭失败,不知道什么原因造成的。
不是
第一,你的 defer 放在错误处理前面就是有问题。第二,我跑了一下你的代码,ioctl 调用报错,但是 close 没有问题
你这个 goroutine 为什么要放在 for{}里面,瞬间 fd 数量都爆了吧
另外用 SIOCGIFNAME 不行吗,你这个 SIOCETHTOOL 在<bits/ioctls.h>都找不到定义
就是一个示例,顺手就写上去了;和问题无关;
尝试下 runtime.KeepAlive? 可能是被 gc 收走了
问题找到了,是我的 et 结构体不全,我在 c 源码里抄了一个完整的 ethtool_cmd 结构体就可以了。
正确做法是先 include c 的 header 然后 import “C”,初始化 C 的结构体
其实 2 楼指出的问题也是正确的,我觉得楼主 golang 应该还没入门,有些问题别急着下结论,以后水平长进了再回头看看吧。
二楼说的 defer close 我没 get 到点,fd 无效会关闭抛出 bad fd 这个我知道,但我的问题是 fd 为什么无效;这相当于没说。另外 import C 这种方式我不喜欢用;还不如纯 C 编译 so 直接给 go 用。
二楼的意思是先检查错误 如果打开错误的话 fd 就是无内容的 defer 就出错了 如果先检查错误再 defer 至少保证 defer 起到应有的关闭 fd 的作用
无效的原因大概是破坏了栈内容吧。。
在Golang中调用Linux系统接口时遇到无法关闭文件描述符(fd)的问题,通常涉及到底层资源管理和系统调用的处理。以下是一些可能的解决步骤和建议:
-
检查文件描述符的正确性: 确保你获取的文件描述符是有效的。在调用
close(fd int)
之前,验证fd
是否已被正确分配且未被其他操作意外关闭。 -
错误处理: 在调用
close
函数后,检查其返回值和errno
,以确认关闭操作是否成功。如果close
返回错误,使用errors.Is
或errors.As
来判断错误类型,这有助于诊断问题。 -
资源泄露检查: 确保没有在程序的其他部分意外保留或复制了文件描述符。这可能导致在尝试关闭时,文件描述符已被其他goroutine使用或关闭。
-
使用defer: 在打开文件或套接字后立即使用
defer close(fd)
,这可以确保即使在发生错误时,文件描述符也能被正确关闭。 -
系统限制: 检查系统级别的文件描述符限制(
ulimit -n
),确保你的程序没有超出这个限制。 -
调试工具: 使用
strace
或lsof
等工具来跟踪系统调用和文件描述符的使用情况,这可以帮助你发现文件描述符管理中的问题。
通过上述步骤,你应该能够定位并解决在Golang中调用Linux系统接口时无法关闭文件描述符的问题。如果问题依旧存在,建议详细审查相关代码和系统日志,或寻求更具体的社区帮助。