我正在研究一个linux守护进程,并且遇到了stdin / stdout的一些问题。通常由于守护程序的性质,您没有任何标准输入或标准输出。但是,我的守护进程中确实有一个函数,当守护进程第一次运行时调用该函数来指定守护进程成功运行所需的不同参数。当调用此函数时,终端变得如此迟缓,以至于我必须启动一个单独的shell并使用top杀死守护进程以获得响应式提示。现在我怀疑这与关闭stdin / stdout的分叉过程有关,但我不太确定如何解决这个问题。如果你们能够了解一下最值得赞赏的情况。感谢。
编辑:
int main(argc, char *argv[]) {
/* setup signal handling */
/* check command line arguments */
pid_t pid, sid;
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
if(pid > 0){
exit(EXIT_SUCCESS);
}
sid = setsid();
if(sid < 0) {
exit(EXIT_FAILURE);
}
umask(027);
/* set syslogging */
/* do some logic to determine wether we are running the daemon for the first time and if we are call the one time function which uses fgets() to recieve some input */
while(1) {
/* do required work */
}
/* do some clean up procedures and exit */
return 0;
}
你们提到使用配置文件。这正是我用来存储通过输入接收的参数的方法。但是我最初仍然需要通过stdin从用户那里获取这些内容。确定我们是否第一次运行的逻辑是基于配置文件的存在。
答案 0 :(得分:14)
通常,守护程序的标准输入应连接到/dev/null
,这样如果从标准输入读取任何内容,则会立即获得EOF。通常,标准输出应连接到文件 - 日志文件或/dev/null
。后者意味着所有写入都将成功,但不会存储任何信息。同样,标准错误应该连接到/dev/null
或日志文件。
所有程序(包括守护进程)都有权假设stdin,stdout和stderr是适当打开的文件流。
守护进程通常适合控制其输入来自何处以及输出进入。输入很少来自/dev/null
以外的其他输入。如果编写的代码在没有标准输出或标准错误的情况下生存(例如,它打开标准日志通道,或者可能使用syslog(3)
),那么关闭stdout和stderr可能是合适的。否则,将它们重定向到/dev/null
可能是合适的,同时仍将消息记录到日志文件中。或者,您可以将stdout和stderr重定向到日志文件 - 请注意不断增长的日志文件。
你的缓慢到不可能的响应时间可能是因为你的程序在某个地方的读取循环中没有注意到EOF。它可能会提示用户输入/ dev / null,并从/ dev / null读取响应,而不是返回“y”或“n”,它会再次尝试,这会严重损坏您的系统。当然,代码存在缺陷,因为它没有处理EOF,并计算得到无效响应的次数,并在合理的尝试次数后停止愚蠢(16,32,64)。如果它希望得到有意义的输入并且继续没有得到它,该程序应该安全地和安全地关闭商店。
答案 1 :(得分:3)
你们提到使用配置文件。这正是我用来存储通过输入接收的参数的方法。但是我最初仍然需要通过stdin从用户那里获取这些内容。确定我们是否第一次运行的逻辑是基于配置文件的存在。
而不是 读取标准输入,让用户自己编写配置文件;在分叉之前检查它是否存在,如果没有则退出并返回错误。在守护程序的联机帮助页中包含示例配置文件,并在守护程序的联机帮助页中记录其格式。你做有一个联机帮助页,是吗?您的配置文件是文本,是吗?
此外,您的守护程序逻辑缺少关键步骤。在分叉之后,但在调用setsid
之前,您需要关闭fds 0,1和2并将它们重新打开到/dev/null
(不尝试使用{{1}执行此操作}和fclose
)。这应该可以解决你的终端问题。
答案 2 :(得分:2)
如果要运行已分离的程序,请使用the shell:(setsid <command> &)
。请勿在您的计划中fork()
class MyObject : public AQObjectInheritingClass
{
Q_OBJECT
...
public Q_SLOTS:
void changeImage()
{
//change image here
}
。
cause sysadmin nightmare或Don't use syslog()
。
更好的是,使用诸如守护进程工具,runit,OpenRC和systemd之类的redirect stdout
or stderr
来为您守护程序。
答案 3 :(得分:1)
你的设计错了。守护进程不应通过stdin获取输入或将输出传递给stdout / stderr。作为守护阶段的一部分,您将关闭这些描述符。守护进程应该从命令行,配置文件或两者中获取配置参数。如果需要运行时输入,则必须读取文件,打开套接字等,但守护程序的重点是它应该能够在没有用户出现在控制台的情况下运行并执行其操作。 / p>
答案 4 :(得分:1)
使用配置文件。不要将STDIN或STDOUT与守护进程一起使用。守护进程意味着在后台中运行而无需用户交互。
答案 5 :(得分:1)
如果你坚持使用stdin / keyboard输入来启动守护进程(例如,为了得到一些你不想存储在文件中的魔术密码),那么在之前处理所有I / O fork()
。