如何在无头(非GUI)环境中检测当前Go进程是否为运行?

How to detect if the current Go process is running in a headless (non-GUI) environment?

我有一个要安装托盘图标的 Go 程序。如果进程是无头的,也就是说,它将无法创建图形用户界面,Go 程序仍然有意义并且应该 运行,但显然它不应安装托盘图标。

Go中检测当前Go进程是否headless的方法是什么?

目前,我使用以下代码:

func isHeadless() bool {
    _, display := os.LookupEnv("DISPLAY")
    return !(runtime.GOOS == "windows" || display)
}

此代码在 "normal" Windows、Linux 或 Mac OS X 上运行良好,我敢打赌它也会 运行 在 FreeBSD、NetBSD、Dragonfly 和许多其他平台上都很好。

不过,该代码显然有很多问题:

那么,在无头环境下,Go 中检测当前进程是否为无头/运行ning 的正确方法是什么?

我不是在寻找变通方法,例如向我的程序添加 --headless 命令行开关。因为,我已经 拥有 无论如何,对于有头脑但希望程序表现得像没有头脑的用户。

在其他一些编程环境中,存在这样的功能。例如,Java 有 java.awt.GraphicsEnvironment.isHeadless(),我正在寻找 Go 中的类似功能。

有些人建议只尝试创建 UI,然后捕获错误。这不起作用,至少不适用于我使用的库。我使用 github.com/getlantern/systray。当 systray.Run() 无法创建 UI 时,进程终止。我设置系统托盘的代码如下所示:

func setupSystray() { // called from main()
    go func() {
        systray.Run(onReady, nil)
    }()
}

func onReady() {
    systray.SetTitle("foo")
    // ...
}

当我 运行 Linux 上的此代码未设置 DISPLAY 时,输出如下:

$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused

(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display: 
$ echo $?
1

可以说这是库中的一个缺陷(我已经在库上创建了一个票证 https://github.com/getlantern/systray/issues/71),但是一些其他 API 和环境仍然提供了一个函数 isHeadless(),我正在寻找 Golang 中的等效项。

我认为您可能从错误的角度解决了这个问题。

可靠地检测到您的程序确实看到了无头机器,IMO,出于多种原因是徒劳的。

因此,我认为我会采用一种通常用于文件系统的方法:

  1. 尝试执行操作。
  2. 如果失败,收集错误。
  3. 分析错误并采取相应措施。

也就是说,只需尝试在您的代码中显式初始化任何与 GUI 堆栈一起工作的客户端(您的)端,捕获任何可能的错误并对其进行分析。如果它说它未能初始化子系统,那么只需举起相关标志并继续。

由于认为缺少 library/solution,我自己创建了一个。 https://github.com/christianhujer/isheadless

用法示例:

package main

import (
    . "fmt"
    . "github.com/christianhujer/isheadless"
    . "os"
)

func main() {
    headless := IsHeadless()
    Fprintf(Stderr, "%s: info: headless: %v\n", Args[0], headless)
    Exit(map[bool]int{true: 0, false: 1}[headless])
}

示例运行:

$ ./isheadless ; echo $?
./isheadless: info: headless: false
1
$ DISPLAY= ./isheadless ; echo $?
./isheadless: info: headless: true
0

好吧,问题的答案正如它所说的那样 就是看看 Java 在它的 isHeadless().

中做了什么

Here 是 OpenJDK 10 所做的。

我不能复制代码,因为它可能会违反其许可证, 但本质上,细分如下:

  1. 获取系统属性"java.awt.headless";如果找到,请使用它。
  2. 获取系统属性"javaplugin.version";如果它存在, 会话不是无头的。使用此值。
  3. 获取系统属性"os.name"。如果字面上包含 子字符串 "OS X" 和系统 属性 "awt.toolkit" 等于字符串 "sun.awt.HToolkit",会话不是无头的。 使用此值。
  4. 检查系统是否属性"os.name" 等于 "Linux"、"SunOS"、"FreeBSD"、"NetBSD"、"OpenBSD" 之一 或 "AIX",如果是,则尝试寻找环境变量 "DISPLAY"; 如果它不存在,则会话是无头的。

如您所见,实际上这张支票很蹩脚 而且我没有看到 Windows.

的任何特殊处理

不过,这准确地回答了你的问题。