gpt4 book ai didi

Linux 显示命令在终端中有效,但在 systemd 服务中无效

转载 作者:IT王子 更新时间:2023-10-29 02:15:15 25 4
gpt4 key购买 nike

我制作了一个网络应用程序来关闭我的电脑屏幕,有一些不同的技术,但它相当简单:

我有一个 html/js 前端检测按钮点击(屏幕打开/屏幕关闭),它通过 ajax 将选项发送到 PHP 后端

然后 php 通过 tcp 端口连接,将选项发送到用 golang 编写的程序

然后我的 golang 程序执行关闭/打开屏幕的命令。它运行的命令是 ("xset -display :0 dpms force off")

我遇到的问题是,该命令仅在我在终端中运行 golang 程序时有效,但当我将其设置为服务时,该命令将无效。

这是 golang 代码:

package main

import (
"os/exec"
"net"
"fmt"
"bufio"
)

func main() {
fmt.Println("Launching server")

ln, _ := net.Listen("tcp", ":7777")
fmt.Println("Listening...\n")

for {
// accept connection on port
conn, _ := ln.Accept()
fmt.Println("New connection")

// listen for message ending in \n
message, _ := bufio.NewReader(conn).ReadString('\n')
rec := string(message)

// remove trailing \n
rec = rec[:len(rec)-1]

fmt.Println("Message Received: ", "\""+rec+"\"")

returnMessage := "fail"

if (rec == "screensOff") {
fmt.Println("Turning off screens...")

//execute screens off command
cmd := exec.Command("xset", "-display", ":0", "dpms", "force", "off")
stdout, err := cmd.Output()

if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(string(stdout))
returnMessage = "done"
}
} else if (rec == "screensOn") {
fmt.Println("Turning on screens...");

//execute screens on command
cmd := exec.Command("xset", "-display", ":0", "dpms", "force", "on")

stdout, err := cmd.Output()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(string(stdout))
returnMessage = "done"
}
returnMessage = "done"
}

conn.Write([]byte(returnMessage + "\n"))

conn.Close()
fmt.Println("Connection closed\n")
}
}

以及相关的PHP代码:

<?php
function sendServiceMessage($message) {
$host = "localhost";
$port = 7777;
$timeout = 30;

// connect to service
$socket = fsockopen($host, $port, $errnum, $errstr, $timeout);
if (!is_resource($socket)) {
exit("connection fail: ".$errnum." ".$errstr);
}
else {
// send message
fputs($socket, $message."\n");

// receive return message
$recieved = "";
while (!feof($socket)) {
$recieved .= fgets ($socket, 1024);
}
}

// close connection
fclose($socket);
if ($recieved == "done") {
return true;
}
return false;
}

sendServiceMessage("screensOff");

我使用 systemd 设置服务,所以在构建程序并将其放在/usr/bin/中

...$ go build screenControl.go
...$ sudo cp screenControl /usr/bin/screenControl

我可以在终端中运行 screenControl 程序,并在网络应用程序中选择“screens off”,一切都按预期工作:

...$ screenControl
Launching server
Listening...

New Connection
Message Received: "screensOff"
Turning off screens...

Connection closed

然后我创建了一个 systemd 单元文件 (/etc/systemd/system/screenControl.service):

[Unit]
Description=Screen control service

[Service]
ExecStart=/usr/bin/screenControl
Restart=on-abort

[Install]
WantedBy=multi-user.target

我启动了服务并检查了它:

...$ systemctl start screenControl
...$ systemctl status screenControl
● screenControl.service - Screen control service
Loaded: loaded (/etc/systemd/system/screenControl.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2015-12-13 22:31:54 GMT; 6s ago
Main PID: 19871 (screenControl)
CGroup: /system.slice/screenControl.service
└─19871 /usr/bin/screenControl

Dec 13 22:31:54 User systemd[1]: Started Screen control service.
Dec 13 22:31:54 User screenControl[19871]: Launching server
Dec 13 22:31:54 User screenControl[19871]: Listening...

所以它正在运行,但是当我现在在网络应用程序中选择屏幕关闭时,没有任何反应......我再次检查了服务状态,它收到了关闭屏幕的消息,但命令正在退出并出现错误:

...
Dec 13 22:31:54 User screenControlTest[19871]: Launching server
Dec 13 22:31:54 User screenControlTest[19871]: Listening...
Dec 13 22:32:25 User screenControlTest[19871]: New connection
Dec 13 22:32:25 User screenControlTest[19871]: Message Received: "screensOff"
Dec 13 22:32:25 User screenControlTest[19871]: Turning off screens...
Dec 13 22:32:25 User screenControlTest[19871]: exit status 1
Dec 13 22:32:25 User screenControlTest[19871]: Connection closed

这里的问题是什么?我怎样才能让该命令作为服务工作?一旦这工作正常,我希望在机器打开时自动启动服务,尽管使用 systemd 我认为这很简单:

...$ systemctl enable screenControl

任何帮助都会很棒,谢谢 :)

编辑

让 golang 程序显示 xset 命令的标准错误后,我现在也有错误消息:

xset:  unable to open display ""

最佳答案

xset 命令只是 X 服务器的一个客户端。它通过检查 DISPLAY 环境变量来确定要与哪个 X 服务器通信,当您将命令作为系统服务运行时不会设置该变量。

即使您确保在运行守护程序时设置了 DISPLAY,它也可能会以不同的用户帐户运行并默认拒绝访问显示。

更好的选择是将您的守护进程作为用户 session 的一部分运行。这将解决身份验证问题(它将像您一样运行)和定位显示的能力(环境变量应该是可见的)。当您未登录时,守护程序不会运行,但这对于这个特定用例可能无关紧要。

您已将您的问题标记为“Ubuntu”,其中 session 仍由 Upstart 管理.您可以通过在 ~/.config/upstart 中创建文件来创建新的用户 session 作业。文件格式的详细信息可以在 init(5) man page 中找到。 .

关于Linux 显示命令在终端中有效,但在 systemd 服务中无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34257440/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com