【发布时间】:2015-12-13 23:00:16
【问题描述】:
我制作了一个网络应用程序来关闭我的电脑屏幕,有几种不同的技术,但很简单:
我有一个 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 程序,然后在 Web 应用程序中选择“屏幕关闭”,一切正常:
...$ 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 ""
【问题讨论】:
-
xwindows 不允许当前会话所有者以外的用户向其发送命令。在调用您的服务之前,从 shell(如您)尝试“xhost +”。可能是root被阻止关闭屏幕。但是当您从 shell 运行命令时它可以工作,因为您拥有会话
-
我停止了服务,尝试了“xhost +”,它说“访问控制已禁用,客户端可以从任何主机连接”然后再次启动服务,但它仍然从 xset 命令获得“退出状态 1” ://
-
您是否生成了与退出代码 1 一起使用的实际错误消息?
-
我玩过 go 并让它向我显示 stderr 输出:(退出状态 1:xset:无法打开显示“”)我想知道它是否像你说的那样,那root 被阻止了,虽然我可以从 root 终端运行 golang 程序并且它可以工作.. 但这是因为我从桌面用户会话启动了 root 会话(通过“sudo -i”)吗?这比我预期的要深,有趣的东西:)
-
当它说显示“”时,这意味着它不知道哪个显示。当您从 go 执行命令行应用程序时,您可以传递环境,尝试使用 DISPLAY=":0"
标签: linux ubuntu service go systemd