Golang读取Linux系统中的proc目录详解
Golang读取Linux系统中的proc目录详解 我正在尝试读取Linux文件系统的proc,更具体地说是comm文件。我的问题是,我的二进制文件在某些进程处卡住,不再执行任何操作。
我尝试使用以下库:“github.com/mitchellh/go-ps”
processes, err := gops.Processes()
if err != nil {
log.Fatal(err)
}
for _, process := range processes {
if process.Executable() == config.Cmd.Processname {
running = true
log.Debug("Process running: " + strconv.FormatBool(running))
return running
}
}
return running
或者传统方法
files, _ := ioutil.ReadDir("/proc")
for _, f := range files {
// check if folder is a integer (process number)
if _, err := strconv.Atoi(f.Name()); err == nil {
// open status file of process
f, err := os.Open("/proc/" + f.Name() + "/status")
if err != nil {
log.Info(err)
return running
}
// read status line by line
scanner := bufio.NewScanner(f)
// check if process name in status of process
for scanner.Scan() {
re := regexp.MustCompile("^Name:\\s*" + config.Cmd.Processname + ".*")
match := re.MatchString(scanner.Text())
if match == true {
running = true
log.Debug("Process running: " + strconv.FormatBool(running))
}
}
if running == true {
return running
}
}
}
我很感谢任何建议。
更多关于Golang读取Linux系统中的proc目录详解的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我自己解决了这个问题。这个库有一个没有任何等待的无限循环。我在这个循环中添加了一个睡眠,现在它运行得很顺利。
更多关于Golang读取Linux系统中的proc目录详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
buddyspencer:
f, err := os.Open("/proc/" + f.Name() + “/status”)
目前已知是这行代码导致了问题。正是因为它,我的程序会自行挂起。
编辑:我使用的某个库运行了一个 Goroutine。只要我禁用这个例程,程序就能正常工作。但问题在于某些情况下我需要这个例程。 以下是引发问题的例程:
func StartElastic() {
done = false
wg.Add(1)
go sendelastic()
}
在处理Linux的/proc目录时,直接读取文件可能会遇到进程状态变化或权限问题导致阻塞。以下是两种改进方法,使用标准库避免依赖第三方包,并处理可能的阻塞情况。
方法1:使用os.ReadDir和上下文超时
通过os.ReadDir读取/proc目录,并为每个进程目录的操作设置超时,防止卡在特定进程上。
package main
import (
"bufio"
"context"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
func isProcessRunning(processName string) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
entries, err := os.ReadDir("/proc")
if err != nil {
return false, err
}
for _, entry := range entries {
select {
case <-ctx.Done():
return false, ctx.Err()
default:
}
if pid, err := strconv.Atoi(entry.Name()); err == nil {
statusFile := filepath.Join("/proc", strconv.Itoa(pid), "comm")
running, err := checkProcessComm(ctx, statusFile, processName)
if err != nil {
continue
}
if running {
return true, nil
}
}
}
return false, nil
}
func checkProcessComm(ctx context.Context, commFile, processName string) (bool, error) {
file, err := os.Open(commFile)
if err != nil {
return false, err
}
defer file.Close()
done := make(chan bool)
go func() {
scanner := bufio.NewScanner(file)
if scanner.Scan() {
name := strings.TrimSpace(scanner.Text())
done <- (name == processName)
} else {
done <- false
}
}()
select {
case result := <-done:
return result, nil
case <-ctx.Done():
return false, ctx.Err()
}
}
func main() {
running, err := isProcessRunning("your_process_name")
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("Process running: %t\n", running)
}
}
方法2:直接读取/proc/[pid]/comm文件
comm文件包含进程的命令名,直接读取它比解析status文件更高效。
package main
import (
"bufio"
"os"
"path/filepath"
"strconv"
"strings"
)
func isProcessRunningViaComm(processName string) (bool, error) {
entries, err := os.ReadDir("/proc")
if err != nil {
return false, err
}
for _, entry := range entries {
if pid, err := strconv.Atoi(entry.Name()); err == nil {
commPath := filepath.Join("/proc", strconv.Itoa(pid), "comm")
data, err := os.ReadFile(commPath)
if err != nil {
continue
}
name := strings.TrimSpace(string(data))
if name == processName {
return true, nil
}
}
}
return false, nil
}
func main() {
running, err := isProcessRunningViaComm("your_process_name")
if err != nil {
panic(err)
}
println("Process running:", running)
}
关键点:
- 使用
os.ReadDir替代ioutil.ReadDir(已弃用)。 - 在
checkProcessComm中使用带超时的上下文,避免无限期阻塞。 - 直接读取
comm文件获取进程名,无需正则匹配。 - 处理文件读取错误时继续循环,不中断整个检查。
这些方法减少了外部依赖,并提高了在/proc目录操作时的可靠性。

