在 Linux 中创建守护进程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17954432/
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
Creating a daemon in Linux
提问by chrisMe
In Linux I want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes are detected, it should write the path to the console where it was started plus a newline.
在 Linux 中,我想添加一个无法停止并监视文件系统更改的守护进程。如果检测到任何更改,它应该将路径写入控制台的启动位置加上换行符。
I already have the filesystem changing code almost ready but I cannot figure out how to create a daemon.
我已经准备好文件系统更改代码,但我不知道如何创建守护程序。
My code is from here: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
我的代码来自这里:http: //www.yolinux.com/TUTORIALS/ForkExecProcesses.html
What to do after the fork?
分叉后怎么办?
int main (int argc, char **argv) {
pid_t pID = fork();
if (pID == 0) { // child
// Code only executed by child process
sIdentifier = "Child Process: ";
}
else if (pID < 0) {
cerr << "Failed to fork" << endl;
exit(1);
// Throw exception
}
else // parent
{
// Code only executed by parent process
sIdentifier = "Parent Process:";
}
return 0;
}
采纳答案by Pascal Werkl
In Linux i want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes would be detected it should write the path to the console where it was started + a newline.
在 Linux 中,我想添加一个无法停止并监视文件系统更改的守护进程。如果检测到任何更改,它应该将路径写入控制台的启动位置 + 换行符。
Daemons work in the background and (usually...) don't belong to a TTY that's why you can't use stdout/stderr in the way you probably want. Usually a syslog daemon (syslogd) is used for logging messages to files (debug, error,...).
守护进程在后台工作并且(通常......)不属于 TTY,这就是为什么您不能以您可能想要的方式使用 stdout/stderr。通常,系统日志守护进程 ( syslogd) 用于将消息记录到文件(调试、错误等)。
Besides that, there are a few required stepsto daemonize a process.
除此之外,还有一些必要的步骤来守护进程。
If I remember correctly these steps are:
如果我没记错的话,这些步骤是:
- forkoff the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
- setsid- Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
- Catch signals- Ignore and/or handle signals.
- fork again& let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
- chdir- Change the working directory of the daemon.
- umask- Change the file mode mask according to the needs of the daemon.
- close- Close all open file descriptors that may be inherited from the parent process.
- 叉掉父进程和让它终止,如果分叉成功。-> 因为父进程已经终止,子进程现在在后台运行。
- setsid- 创建一个新会话。调用进程成为新会话的领导者和新进程组的进程组领导。该进程现在与其控制终端 (CTTY) 分离。
- 捕捉信号- 忽略和/或处理信号。
- 再次 fork 并让父进程终止以确保您摆脱会话引导进程。(只有会话负责人可以再次获得 TTY。)
- chdir- 更改守护进程的工作目录。
- umask- 根据守护进程的需要更改文件模式掩码。
- close- 关闭所有可能从父进程继承的打开的文件描述符。
To give you a starting point: Look at this skeleton code that shows the basic steps. This code can now also be forked on GitHub: Basic skeleton of a linux daemon
给你一个起点:看看这个显示基本步骤的骨架代码。此代码现在也可以在 GitHub 上分叉:Linux 守护进程的基本框架
/*
* daemonize.c
* This example daemonizes a process, writes a few log messages,
* sleeps 20 seconds and terminates afterwards.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
static void skeleton_daemon()
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
skeleton_daemon();
while (1)
{
//TODO: Insert daemon code here.
syslog (LOG_NOTICE, "First daemon started.");
sleep (20);
break;
}
syslog (LOG_NOTICE, "First daemon terminated.");
closelog();
return EXIT_SUCCESS;
}
- Compile the code:
gcc -o firstdaemon daemonize.c
- Start the daemon:
./firstdaemon
Check if everything is working properly:
ps -xj | grep firstdaemon
The output should be similar to this one:
- 编译代码:
gcc -o firstdaemon daemonize.c
- 启动守护进程:
./firstdaemon
检查一切是否正常:
ps -xj | grep firstdaemon
输出应该类似于这个:
+------+------+------+------+-----+-------+------+------+------+-----+ | PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | TIME | CMD | +------+------+------+------+-----+-------+------+------+------+-----+ | 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ | +------+------+------+------+-----+-------+------+------+------+-----+
What you should see here is:
你应该在这里看到的是:
- The daemon has no controlling terminal (TTY = ?)
- The parent process ID (PPID) is 1(The init process)
- The PID != SIDwhich means that our process is NOT the session leader
(because of the second fork()) - Because PID != SID our process can't take control of a TTY again
- 守护进程没有控制终端(TTY = ?)
- 父进程 ID ( PPID) 为1(初始化进程)
- 该PID!= SID,这意味着我们的进程不是会话组长
(因为第二叉()) - 因为 PID != SID 我们的进程不能再次控制 TTY
Reading the syslog:
读取系统日志:
- Locate your syslog file. Mine is here:
/var/log/syslog
Do a:
grep firstdaemon /var/log/syslog
The output should be similar to this one:
- 找到您的系统日志文件。我的在这里:
/var/log/syslog
做一个:
grep firstdaemon /var/log/syslog
输出应该类似于这个:
firstdaemon[3387]: First daemon started. firstdaemon[3387]: First daemon terminated.
A note:In reality you would also want to implement a signal handler and set up the logging properly (Files, log levels...).
注意:实际上,您还希望实现一个信号处理程序并正确设置日志记录(文件、日志级别...)。
Further reading:
进一步阅读:
回答by Magn3s1um
A daemon is just a process in the background. If you want to start your program when the OS boots, on linux, you add your start command to /etc/rc.d/rc.local (run after all other scripts) or /etc/startup.sh
守护进程只是后台的一个进程。如果你想在操作系统启动时启动你的程序,在 linux 上,你将启动命令添加到 /etc/rc.d/rc.local(在所有其他脚本之后运行)或 /etc/startup.sh
On windows, you make a service, register the service, and then set it to start automatically at boot in administration -> services panel.
在 Windows 上,您创建一个服务,注册该服务,然后在管理 -> 服务面板中将其设置为在启动时自动启动。
回答by Doug Morrow
By calling fork() you've created a child process. If the fork is successful (fork returned a non-zero PID) execution will continue from this point from within the child process. In this case we want to gracefully exit the parent process and then continue our work in the child process.
通过调用 fork() 您已经创建了一个子进程。如果 fork 成功(fork 返回一个非零的 PID)执行将从子进程中的这一点继续。在这种情况下,我们希望优雅地退出父进程,然后在子进程中继续我们的工作。
Maybe this will help: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html
也许这会有所帮助:http: //www.netzmafia.de/skripten/unix/linux-daemon-howto.html
回答by Edwin Buck
I can stop at the first requirement "A daemon which cannot be stopped..."
我可以停在第一个要求“无法停止的守护进程......”
Not possible my friend; however, you can achieve the same with a much better tool, a kernel module.
不可能,我的朋友;但是,您可以使用更好的工具内核模块来实现相同的功能。
http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring
http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring
All daemons can be stopped. Some are more easily stopped than others. Even a daemon pair with the partner in hold down, respawning the partner if lost, can be stopped. You just have to work a little harder at it.
所有守护进程都可以停止。有些比其他更容易停止。即使是一个守护进程对与合作伙伴处于按住状态,如果丢失,则可以停止重生合作伙伴。你只需要更加努力地工作。
回答by ChuckCottrill
You cannot create a process in linux that cannot be killed. The root user (uid=0) can send a signal to a process, and there are two signals which cannot be caught, SIGKILL=9, SIGSTOP=19. And other signals (when uncaught) can also result in process termination.
你不能在 linux 中创建一个不能被杀死的进程。root 用户(uid=0)可以向进程发送信号,有两个信号不能被捕获,SIGKILL=9,SIGSTOP=19。其他信号(未捕获时)也可能导致进程终止。
You may want a more general daemonize function, where you can specify a name for your program/daemon, and a path to run your program (perhaps "/" or "/tmp"). You may also want to provide file(s) for stderr and stdout (and possibly a control path using stdin).
您可能需要一个更通用的 daemonize 函数,您可以在其中指定程序/守护程序的名称,以及运行程序的路径(可能是“/”或“/tmp”)。您可能还想为 stderr 和 stdout 提供文件(可能还有使用 stdin 的控制路径)。
Here are the necessary includes:
以下是必要的包括:
#include <stdio.h> //printf(3)
#include <stdlib.h> //exit(3)
#include <unistd.h> //fork(3), chdir(3), sysconf(3)
#include <signal.h> //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h> //syslog(3), openlog(3), closelog(3)
And here is a more general function,
这是一个更通用的函数,
int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
if(!path) { path="/"; }
if(!name) { name="medaemon"; }
if(!infile) { infile="/dev/null"; }
if(!outfile) { outfile="/dev/null"; }
if(!errfile) { errfile="/dev/null"; }
//printf("%s %s %s %s\n",name,path,outfile,infile);
pid_t child;
//fork, detach from process group leader
if( (child=fork())<0 ) { //failed fork
fprintf(stderr,"error: failed fork\n");
exit(EXIT_FAILURE);
}
if (child>0) { //parent
exit(EXIT_SUCCESS);
}
if( setsid()<0 ) { //failed to become session leader
fprintf(stderr,"error: failed setsid\n");
exit(EXIT_FAILURE);
}
//catch/ignore signals
signal(SIGCHLD,SIG_IGN);
signal(SIGHUP,SIG_IGN);
//fork second time
if ( (child=fork())<0) { //failed fork
fprintf(stderr,"error: failed fork\n");
exit(EXIT_FAILURE);
}
if( child>0 ) { //parent
exit(EXIT_SUCCESS);
}
//new file permissions
umask(0);
//change to path directory
chdir(path);
//Close all open file descriptors
int fd;
for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd )
{
close(fd);
}
//reopen stdin, stdout, stderr
stdin=fopen(infile,"r"); //fd=0
stdout=fopen(outfile,"w+"); //fd=1
stderr=fopen(errfile,"w+"); //fd=2
//open syslog
openlog(name,LOG_PID,LOG_DAEMON);
return(0);
}
Here is a sample program, which becomes a daemon, hangs around, and then leaves.
这是一个示例程序,它变成了一个守护进程,徘徊,然后离开。
int
main()
{
int res;
int ttl=120;
int delay=5;
if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
fprintf(stderr,"error: daemonize failed\n");
exit(EXIT_FAILURE);
}
while( ttl>0 ) {
//daemon code here
syslog(LOG_NOTICE,"daemon ttl %d",ttl);
sleep(delay);
ttl-=delay;
}
syslog(LOG_NOTICE,"daemon ttl expired");
closelog();
return(EXIT_SUCCESS);
}
Note that SIG_IGN indicates to catch and ignore the signal. You could build a signal handler that can log signal receipt, and set flags (such as a flag to indicate graceful shutdown).
请注意,SIG_IGN 表示捕获并忽略信号。您可以构建一个可以记录信号接收的信号处理程序,并设置标志(例如指示正常关闭的标志)。
回答by weiyin
Try using the daemon
function:
尝试使用该daemon
功能:
#include <unistd.h>
int daemon(int nochdir, int noclose);
From the man page:
从手册页:
The daemon() function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons.
If nochdir is zero, daemon() changes the calling process's current working directory to the root directory ("/"); otherwise, the current working directory is left unchanged.
If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made to these file descriptors.
daemon() 函数适用于希望将自身与控制终端分离并作为系统守护进程在后台运行的程序。
如果 nochdir 为零,daemon() 将调用进程的当前工作目录更改为根目录(“/”);否则,当前工作目录保持不变。
如果 noclose 为零,daemon() 将标准输入、标准输出和标准错误重定向到 /dev/null;否则,不会对这些文件描述符进行任何更改。
回答by patryk.beza
man 7 daemon
describes how to create daemon in great detail. My answer is just excerpt from this manual.
man 7 daemon
详细描述了如何创建守护进程。我的回答只是摘自本手册。
There are at least two types of daemons:
至少有两种类型的守护进程:
SysV Daemons
SysV 守护进程
If you are interested in traditional SysVdaemon, you should implement the following steps:
- Close all open file descriptors except standard input, output, and error(i.e. the first three file descriptors 0, 1, 2). This ensures that no accidentally passed file descriptor stays around in the daemon process. On Linux, this is best implemented by iterating through
/proc/self/fd
, with a fallback of iterating from file descriptor 3 to the value returned bygetrlimit()
forRLIMIT_NOFILE
.- Resetall signal handlers to their default. This is best done by iterating through the available signals up to the limit of
_NSIG
and resetting them toSIG_DFL
.- Reset the signal mask using
sigprocmask()
.- Sanitize the environment block, removing or resetting environment variables that might negatively impact daemon runtime.
- Call
fork()
, to create a background process.- In the child, call
setsid()
to detach from any terminal and create an independent session.- In the child, call
fork()
again, to ensure that the daemon can never re-acquire a terminal again.- Call
exit()
in the first child, so that only the second child (the actual daemon process) stays around. This ensures that the daemon process is re-parented to init/PID 1, as all daemons should be.- In the daemon process, connect
/dev/null
to standard input, output, and error.- In the daemon process, reset the
umask
to 0, so that the file modes passed toopen()
,mkdir()
and suchlike directly control the access mode of the created files and directories.- In the daemon process, changethe current directory to the root directory (
/
), in order to avoid that the daemon involuntarily blocks mount points from being unmounted.- In the daemon process, write the daemon PID(as returned by
getpid()
) to a PID file, for example/run/foobar.pid
(for a hypothetical daemon "foobar") to ensure that the daemon cannot be started more than once. This must be implemented in race-free fashion so that the PID file is only updated when it is verified at the same time that the PID previously stored in the PID file no longer exists or belongs to a foreign process.- In the daemon process, drop privileges, if possible and applicable.
- From the daemon process, notify the original process started that initialization is complete. This can be implemented via an unnamed pipe or similar communication channel that is created before the first
fork()
and hence available in both the original and the daemon process.- Call
exit()
in the original process. The process that invoked the daemon must be able to rely on that thisexit()
happens afterinitialization is complete and all external communication channels are established and accessible.
- 关闭除标准输入、输出和错误之外的所有打开的文件描述符(即前三个文件描述符 0、1、2)。这确保了在守护进程中不会有意外传递的文件描述符。在 Linux 上,这最好通过迭代来实现
/proc/self/fd
,并回退从文件描述符 3 迭代到getrlimit()
for返回的值RLIMIT_NOFILE
。- 将所有信号处理程序重置为其默认值。最好通过将可用信号迭代到 的限制
_NSIG
并将它们重置为 来完成SIG_DFL
。- 使用 重置信号掩码
sigprocmask()
。- 清理环境块,删除或重置可能对守护程序运行时产生负面影响的环境变量。
- 调用
fork()
, 创建后台进程。- 在子
setsid()
进程中,调用detach 从任何终端并创建一个独立的session。- 在子
fork()
进程中,再次调用,以确保守护进程永远不会再次重新获取终端。- 调用
exit()
第一个孩子,以便只有第二个孩子(实际的守护进程)留下来。这可确保守护进程重新成为 init/PID 1 的父级,所有守护进程都应该如此。- 在守护进程中,连接
/dev/null
到标准input、output和error。- 在守护进程,重置
umask
为0,从而使文件模式传递给open()
,mkdir()
以及诸如此类的直接控制创建文件和目录的访问模式。- 在守护进程,改变当前目录为根目录(
/
,按顺序),以避免该守护进程不由自主块从被卸载安装点。- 在守护进程中,将守护进程PID(由 返回
getpid()
)写入 PID 文件,例如/run/foobar.pid
(对于假设的守护进程“foobar”),以确保守护进程不能多次启动。这必须以无竞争的方式实现,以便 PID 文件仅在同时验证之前存储在 PID 文件中的 PID 不再存在或属于外部进程时才更新。- 在守护进程中,如果可能和适用,删除权限。
- 从守护进程通知原启动的进程初始化完成。这可以通过未命名管道或类似的通信通道来实现,该通道在第一个之前创建
fork()
,因此在原始进程和守护进程中都可用。- 调用
exit()
原进程。调用守护进程的进程必须能够依赖于在初始化完成并且所有外部通信通道建立和可访问之后exit()
发生这种情况。
Note this warning:
请注意此警告:
The BSD
daemon()
function should notbe used, as it implements only a subsetof these steps.A daemon that needs to provide compatibilitywith SysV systems should implement the scheme pointed out above. However, it is recommended to make this behavior optional and configurable via a command line argument to ease debugging as well as to simplify integration into systems using systemd.
不应使用BSD
daemon()
函数,因为它仅实现了这些步骤的一个子集。需要提供与 SysV 系统兼容的守护进程应该实现上面指出的方案。但是,建议通过命令行参数使此行为可选和可配置,以简化调试并使用 systemd 简化与系统的集成。
Note that daemon()
is not POSIXcompliant.
New-Style Daemons
新型守护进程
For new-style daemons the following stepsare recommended:
对于新型守护进程,建议执行以下步骤:
- If
SIGTERM
is received, shut down the daemon and exit cleanly.- If
SIGHUP
is received, reload the configuration files, if this applies.- Provide a correct exit code from the main daemon process, as this is used by the init system to detect service errors and problems. It is recommended to follow the exit code scheme as defined in the LSB recommendations for SysV init scripts.
- If possible and applicable, expose the daemon's control interface via the D-Bus IPCsystem and grab a bus name as last step of initialization.
- For integration in systemd, provide a .serviceunitfile that carries information about starting, stopping and otherwise maintaining the daemon. See
systemd.service(5)
for details.- As much as possible, rely on the init system's functionality to limit the access of the daemon to files, services and other resources, i.e. in the case of systemd, rely on systemd's resource limit controlinstead of implementing your own, rely on systemd's privilege droppingcode instead of implementing it in the daemon, and similar. See
systemd.exec(5)
for the available controls.- If D-Busis used, make your daemon bus-activatable by supplying a D-Bus service activation configuration file. This has multiple advantages: your daemon may be started lazily on-demand; it may be started in parallel to other daemons requiring it — which maximizes parallelization and boot-up speed; your daemon can be restarted on failure without losing any bus requests, as the bus queues requests for activatable services. See belowfor details.
- If your daemon provides services to other local processes or remote clients via a socket, it should be made socket-activatablefollowing the scheme pointed out below. Like D-Bus activation, this enables on-demand starting of services as well as it allows improved parallelization of service start-up. Also, for state-less protocols (such as syslog, DNS), a daemon implementing socket-based activation can be restarted without losing a single request. See belowfor details.
- If applicable, a daemon should notify the init system about startup completion or status updates via the
sd_notify(3)
interface.- Instead of using the
syslog()
call to log directly to the system syslog service, a new-style daemon may choose to simply log to standard error viafprintf()
, which is then forwarded to syslog by the init system. If log levels are necessary, these can be encoded by prefixing individual log lines with strings like "<4>" (for log level 4 "WARNING" in the syslog priority scheme), following a similar style as the Linux kernel'sprintk()
level system. For details, seesd-daemon(3)
andsystemd.exec(5)
.
- 如果
SIGTERM
收到,请关闭守护程序并干净地退出。- 如果
SIGHUP
收到,则重新加载配置文件(如果适用)。- 从主守护进程提供正确的退出代码,因为 init 系统使用它来检测服务错误和问题。建议遵循SysV init 脚本的LSB 建议中定义的退出代码方案。
- 如果可能和适用,通过D-Bus IPC系统公开守护进程的控制接口,并获取总线名称作为初始化的最后一步。
- 为了在 systemd 中集成,提供一个.service单元文件,其中包含有关启动、停止和以其他方式维护守护进程的信息。详情请参阅
systemd.service(5)
。- 尽量依靠init系统的功能来限制daemon对文件、服务等资源的访问,即在systemd的情况下,依靠systemd的资源限制控制而不是自己实现,依靠systemd的权限下降代码而不是在守护进程中实现它,等等。有关
systemd.exec(5)
可用控件的信息,请参阅。- 如果使用D-Bus,请通过提供 D-Bus 服务激活配置文件使您的守护程序总线可激活。这有很多优点:你的守护进程可以按需延迟启动;它可以与其他需要它的守护进程并行启动——这最大限度地提高了并行化和启动速度;您的守护进程可以在失败时重新启动而不会丢失任何总线请求,因为总线将请求排队可激活的服务。详情请见下文。
- 如果你的守护进程通过一个套接字提供给当地其他进程或远程客户提供服务,应当取得插座活化方案如下指出以下。与 D-Bus 激活一样,这支持按需启动服务,并允许改进服务启动的并行化。此外,对于无状态协议(例如 syslog、DNS),可以重新启动实现基于套接字的激活的守护进程而不会丢失单个请求。详情请见下文。
- 如果适用,守护进程应通过
sd_notify(3)
接口通知 init 系统启动完成或状态更新。- 与使用
syslog()
调用直接登录到系统 syslog 服务不同,新型守护进程可以选择通过 简单地登录到标准错误fprintf()
,然后由 init 系统转发到 syslog。如果需要日志级别,可以通过在单独的日志行前面加上像“<4>”这样的字符串(对于 syslog 优先级方案中的日志级别 4“警告”)进行编码,遵循与 Linux 内核printk()
级别系统类似的风格。有关详细信息,请参阅sd-daemon(3)
和systemd.exec(5)
。
To learn more read whole man 7 daemon
.
要了解更多信息,请阅读全文man 7 daemon
。
回答by danday74
If your app is one of:
如果您的应用是以下之一:
{
".sh": "bash",
".py": "python",
".rb": "ruby",
".coffee" : "coffee",
".php": "php",
".pl" : "perl",
".js" : "node"
}
and you don't mind a NodeJS dependency then install NodeJS and then:
并且您不介意 NodeJS 依赖项,然后安装 NodeJS,然后:
npm install -g pm2
pm2 start yourapp.yourext --name "fred" # where .yourext is one of the above
pm2 start yourapp.yourext -i 0 --name "fred" # run your app on all cores
pm2 list
To keep all apps running on reboot (and daemonise pm2):
要保持所有应用程序在重新启动时运行(并守护 pm2):
pm2 startup
pm2 save
Now you can:
现在你可以:
service pm2 stop|restart|start|status
(also easily allows you to watch for code changes in your app directory and auto restart the app process when a code change happens)
(还可以轻松地让您观察应用程序目录中的代码更改,并在发生代码更改时自动重启应用程序进程)
回答by Fabiano Traple
Daemon Template
守护程序模板
I wrote a daemon template following the new-style daemon: link
我按照新式守护程序编写了一个守护程序模板:链接
You can find the entire template code on GitHub: here
你可以在 GitHub 上找到完整的模板代码:这里
Main.cpp
主程序
// This function will be called when the daemon receive a SIGHUP signal.
void reload() {
LOG_INFO("Reload function called.");
}
int main(int argc, char **argv) {
// The Daemon class is a singleton to avoid be instantiate more than once
Daemon& daemon = Daemon::instance();
// Set the reload function to be called in case of receiving a SIGHUP signal
daemon.setReloadFunction(reload);
// Daemon main loop
int count = 0;
while(daemon.IsRunning()) {
LOG_DEBUG("Count: ", count++);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
LOG_INFO("The daemon process ended gracefully.");
}
Daemon.hpp
守护进程
class Daemon {
public:
static Daemon& instance() {
static Daemon instance;
return instance;
}
void setReloadFunction(std::function<void()> func);
bool IsRunning();
private:
std::function<void()> m_reloadFunc;
bool m_isRunning;
bool m_reload;
Daemon();
Daemon(Daemon const&) = delete;
void operator=(Daemon const&) = delete;
void Reload();
static void signalHandler(int signal);
};
Daemon.cpp
守护进程
Daemon::Daemon() {
m_isRunning = true;
m_reload = false;
signal(SIGINT, Daemon::signalHandler);
signal(SIGTERM, Daemon::signalHandler);
signal(SIGHUP, Daemon::signalHandler);
}
void Daemon::setReloadFunction(std::function<void()> func) {
m_reloadFunc = func;
}
bool Daemon::IsRunning() {
if (m_reload) {
m_reload = false;
m_reloadFunc();
}
return m_isRunning;
}
void Daemon::signalHandler(int signal) {
LOG_INFO("Interrup signal number [", signal,"] recived.");
switch(signal) {
case SIGINT:
case SIGTERM: {
Daemon::instance().m_isRunning = false;
break;
}
case SIGHUP: {
Daemon::instance().m_reload = true;
break;
}
}
}
daemon-template.service
守护进程-template.service
[Unit]
Description=Simple daemon template
After=network.taget
[Service]
Type=simple
ExecStart=/usr/bin/daemon-template --conf_file /etc/daemon-template/daemon-tenplate.conf
ExecReload=/bin/kill -HUP $MAINPID
User=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=daemon-template
[Install]
WantedBy=multi-user.target