Linux 守护进程和 STDIN/STDOUT

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4869860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:41:47  来源:igfitidea点击:

A Linux Daemon and the STDIN/STDOUT

clinuxbash

提问by Error1f1f

I am working on a linux daemon and having some issues with the stdin/stdout. Normally because of the nature of a daemon you do not have any stdin or stdout. However, I do have a function in my daemon that is called when the daemon runs for the first time to specify different parameters that are required for the daemon to run successfully. When this function is called the terminal becomes so sluggish that I have to launch a seperate shell and kill the daemon with top to get a responsive prompt back. Now I suspect that this has something to do with the forking process closing the stdin/stdout but I am not quite sure how I could work around this. If you guys could shed some light on the situation that would be most appreciated. Thanks.

我正在开发一个 linux 守护进程,并且在 stdin/stdout 上遇到了一些问题。通常,由于守护程序的性质,您没有任何标准输入或标准输出。但是,我的守护程序中确实有一个函数,该函数在守护程序第一次运行时被调用,以指定守护程序成功运行所需的不同参数。当这个函数被调用时,终端变得如此缓慢,以至于我不得不启动一个单独的 shell 并用 top 杀死守护进程以获得响应提示。现在我怀疑这与关闭标准输入/标准输出的分叉过程有关,但我不太确定如何解决这个问题。如果你们能对最受赞赏的情况有所了解。谢谢。

Edit:

编辑:

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;
}

You guys mention using a config file. This is is exactly what I do to store the parameters recieved via input. However I still initially need to get these from the user via the stdin. The logic for determining whether we are running for the first time is based off of the existence of the config file.

你们提到使用配置文件。这正是我为存储通过输入接收到的参数所做的工作。但是,我最初仍然需要通过标准输入从用户那里获取这些信息。确定我们是否第一次运行的逻辑是基于配置文件的存在。

采纳答案by zwol

You guys mention using a config file. This is is exactly what I do to store the parameters recieved via input. However I still initially need to get these from the user via the stdin. The logic for determining whether we are running for the first time is based off of the existence of the config file.

你们提到使用配置文件。这正是我为存储通过输入接收到的参数所做的工作。但是,我最初仍然需要通过标准输入从用户那里获取这些信息。确定我们是否第一次运行的逻辑是基于配置文件的存在。

Instead ofreading stdin, have the user write the config file themselves; check for its existence beforeforking, and exit with an error if it doesn't. Include a sample config file with the daemon, and document its format in your daemon's manpage. You dohave a manpage, yes? Your config file istextual, yes?

不是读取标准输入,而是让用户自己编写配置文件;分叉之前检查它是否存在,如果不存在则退出并显示错误。在守护程序中包含一个示例配置文件,并在守护程序的联机帮助页中记录其格式。你这样做有一个手册页,是吗?你的配置文件文本文件,是吗?

Also, your daemonization logic is missing a key step. After forking, but before calling setsid, you need to close fds 0, 1, and 2 and reopen them to /dev/null(do notattempt to do this with fcloseand fopen). That should fix your sluggish terminal problem.

此外,您的守护程序逻辑缺少一个关键步骤。分叉后,但调用之前setsid,您需要关闭FDS 0,1,2,然后重新打开他们/dev/null(不要尝试与要做到这一点fclosefopen)。这应该可以解决您缓慢的终端问题。

回答by par

Your design is wrong. Daemon processes should not take input via stdin or deliver output to stdout/stderr. You'll close those descriptors as part of the daemonizing phase. Daemons should take configuration parameters from the command line, a config file, or both. If runtime-input is required you'll have to read a file, open a socket, etc., but the point of a daemon is that it should be able to run and do its thing without a user being present at the console.

你的设计是错误的。守护进程不应通过 stdin 获取输入或将输出传送到 stdout/stderr。作为守护进程的一部分,您将关闭这些描述符。守护进程应该从命令行、配置文件或两者中获取配置参数。如果需要运行时输入,则必须读取文件、打开套接字等,但守护程序的重点是它应该能够在没有用户出现在控制台的情况下运行并执行其操作。

回答by Jonathan Leffler

Normally, the standard input of a daemon should be connected to /dev/null, so that if anything is read from standard input, you get an EOF immediately. Normally, standard output should be connected to a file - either a log file or /dev/null. The latter means all writes will succeed, but no information will be stored. Similarly, standard error should be connected to /dev/nullor to a log file.

通常,守护进程的标准输入应该连接到/dev/null,这样如果从标准输入读取任何内容,您会立即获得 EOF。通常,标准输出应连接到文件 - 日志文件或/dev/null. 后者意味着所有写入都会成功,但不会存储任何信息。同样,标准错误应该连接到/dev/null或连接到日志文件。

All programs, including daemons, are entitled to assume that stdin, stdout and stderr are appropriately opened file streams.

所有程序,包括守护进程,都有权假定 stdin、stdout 和 stderr 是适当打开的文件流。

It is usually appropriate for a daemon to control where its input comes from and outputs go to. There is seldom occasion for input to come from other than /dev/null. If the code was written to survive without standard output or standard error (for example, it opens a standard log channel, or perhaps uses syslog(3)) then it may be appropriate to close stdout and stderr. Otherwise, it is probably appropriate to redirect them to /dev/null, while still logging messages to a log file. Alternatively, you can redirect both stdout and stderr to a log file - beware continuously growing log files.

守护进程通常适合控制其输入来自何处和输出去向。很少有输入来自/dev/null. 如果代码被编写为在没有标准输出或标准错误的情况下继续存在(例如,它打开一个标准日志通道,或者可能使用syslog(3)),那么关闭 stdout 和 stderr 可能是合适的。否则,将它们重定向到 可能是合适的/dev/null,同时仍将消息记录到日志文件。或者,您可以将 stdout 和 stderr 都重定向到日志文件 - 注意不断增长的日志文件。

Your sluggish-to-impossible response time might be because your program is not paying attention to EOF in a read loop somewhere. It might be prompting for user input on /dev/null, and reading a response from /dev/null, and not getting a 'y' or 'n' back, it tries again, which chews up your system horribly. Of course, the code is flawed in not handling EOF, and counting the number of times it gets an invalid response and stopping being silly after a reasonable number of attempts (16, 32, 64). The program should shut up shop sanely and safely if it expects a meaningful input and continues not to get it.

您从缓慢到不可能的响应时间可能是因为您的程序没有注意某个读取循环中的 EOF。它可能会提示用户在 /dev/null 上输入,并从 /dev/null 读取响应,但没有得到 'y' 或 'n' 返回,它再次尝试,这会严重破坏您的系统。当然,该代码在不处理 EOF 方面存在缺陷,并且计算它得到无效响应的次数并在合理的尝试次数(16、32、64)后停止愚蠢。如果该程序期望有意义的输入并且继续没有得到它,它应该理智而安全地关闭商店。

回答by Scott M.

Use a config file. Do not use STDIN or STDOUT with a daemon. Daemons are meant to run in the backgroundwith no user interaction.

使用配置文件。不要将 STDIN 或 STDOUT 与守护程序一起使用。守护进程旨在在没有用户交互的情况后台运行。

回答by mvds

If you insist on using stdin/keyboard input to fire up the daemon (e.g. to get some magic passphrase you wouldn't want to store in a file) then handle all I/O beforethe fork().

如果你坚持使用标准输入/键盘输入火起来的守护进程(如获得一些神奇的密码,你不会想在文件存储),然后处理所有的I / O之前fork()

回答by FRIdSUN

If you want to run your program detached, use the shell: (setsid <command> &). Do not fork()inside your program, which will cause sysadmin nightmare.

如果要独立运行程序,请使用shell: (setsid <command> &)。不要fork()在你的程序里面,这会造成系统管理员的噩梦

Don't use syslog()nor redirect stdoutor stderr.

不要使用syslog()重定向stdoutstderr.

Better yet, use a daemon managersuch as daemon tools, runit, OpenRC and systemd, to daemonize your program for you.

更好的是,使用守护程序管理器,例如守护程序工具、runit、OpenRC 和 systemd,为您守护程序。