Linux系统守护进程怎么理解
这篇文章主要为大家分析了Linux系统守护进程怎么理解的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习"Linux系统守护进程怎么理解"的知识吧。
什么是守护进程?例如淘宝、支付宝等必须7*24小时不停的运行,这就是一个非常典型的守护进程。
1、查看系统中的进程
ps axj1
参数a表示不仅列当前用户的进程,也列出所有其他用户的进程, 参数x表示不仅列有控制终端的进程,也列出所无控制终端的进程, 参数j表示列出与作业控制相关的信息。
凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。在COMMAND一列用[]括起来的 名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表示Kernel。init进程我们已经很熟悉了,udevd负责维 护/dev目录下的设备⽂文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件,可以看出,守护进程通 常采用以d结尾的名字,表示Daemon。
2、setsid函数 1>创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。
#include pid_t setsid(void);12
返回值:该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。
2>需要注意的是,,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。 解决办法:先fork再调用setsid,fork创建的子进程和父进程在同一个进 程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子 进程中调用setsid就不会有问题了。
3>成功调用该函数的结果是: \1. 创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。 \2. 创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。 \3. 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。
3、创建守护进程的步骤 1>调用umask将文件模式创建屏蔽字设置为0.
umask(0);//umask必须清0,否则创建文件受系统默认权限的影响1
文件权限掩码是屏蔽掉文件权限中的对应位。由于使用fork()函数新创建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带了很多的麻烦(比如父进程中的文件没有执行文件的权限,然而在子进程中希望执行相应的文件这个时候就会出问题)。因此在子进程中要把文件的权限掩码设置成为0,即在此时有最大的权限,这样可以大大增强该守护进程的灵活性。
2>调用fork,父进程退出(exit)。 原因: 1)如果该守护进程是作为一条简单的shell命令启动的,那么⽗父进程终止使得shell认为该命令已经执行完毕。 2)保证子进程不是一个进程组的组长进程。
3>调用setsid创建一个新会话。 setsid会导致: 1)调用进程成为新会话的首进程。 2)调用进程成为一个进程组的组长进程 。 3)调用进程没有控制终端。(再次fork一次,保证daemon进程,之后不会打开tty设备)
调用setsid的原因: 由于创建守护进程的第一步是调用fork()函数来创建子进程,再将父进程退出。由于在调用了fork()函数的时候,子进程拷贝了父进程的会话期、进程组、控制终端等资源、虽然父进程退出了,但是会话期、进程组、控制终端等并没有改变,因此,需要用setsid()韩式来时该子进程完全独立出来,从而摆脱其他进程的控制。
4>将当前工作目录更改为根目录。 防止当前目录有一个目录被删除,导致守护进程无效。 使用fork()创建的子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后使用会造成很多的麻烦。因此通常的做法是让"/"作为守护进程的当前目录,当然也可以指定其他的别的目录来作为守护进程的工作目录。
5>关闭不再需要的文件描述符。 同文件权限码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些文件被打开的文件可能永远不会被守护进程读写,如果不进行关闭的话将会浪费系统的资源,造成进程所在的文件系统无法卸下以及引起预料的错误。
如:关闭标准输入流、标准输出流、标准错误流。
close(0); close(1); close(2);123
6>其他:忽略SIGCHLD信号。
signal(SIGCHLD,SIG_IGN);1
4、自己创建守护进程:
1 /************************************** 2 *文件说明:mydaemon.c 3 *作者:段晓雪 4 *创建时间:2024年11月20日 星期三 12时26分43秒 5 *开发环境:Kali Linux/g++ v6.3.0 6 ****************************************/ 7 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 void mydaemon() 16 { 17 umask(0);//将文件模式创建屏蔽字设为0 18 pid_t pid = fork();//创建子进程 19 if(pid == -1) 20 perror("fork error"); 21 else if(pid == 0)//child 22 { 23 setsid();//创建新会话 24 if(chdir("/")ps axj | grep mydaemon查看精灵进程: 5、调用系统函数daemon创建守护进程 #include int daemon(int nochdir, int noclose);121>daemon函数主要用于希望脱离控制台,以守护进程的形式在后台运行的程序。 2>当nochdir为0时,daemon将更改当前进程的目录为root("/")目录。 3> 当noclose为0时,daemon将进程的STDIN,STDOUT,STDERR都重定向到/dev/null。 /dev/null:linux下的黑洞,写入的所有数据会直接丢弃。用daemon函数创建守护进程: 1 /************************************** 2 *文件说明:daemon.c 3 *作者:段晓雪 4 *创建时间:2024年11月22日 星期五 06时53分52秒 5 *开发环境:Kali Linux/g++ v6.3.0 6 ****************************************/ 7 8 #include 9 #include 10 11 int main() 12 { 13 daemon(1,1);//创建守护进程 14 while(1); 15 return 0; 16 }12345678910111213141516三、如何杀死守护进程?1> 利用ps axj | grep 守护进程名字找到相应的守护进程,然后用kill -9 进程号将对应进程杀死。 2>利用ps -ef命令查找相应的守护进程,再用kill命令将其杀死。 …… 3>也可创建shell脚本对进程的启动、关闭、重启进行自动管理。四、为什么有人创建守护进程会fork两次?一个daemon函数常见的实现: int daemon(void) { pid_t pid = fork(); //第一次fork if( pid != 0 ) exit(0);//parent //first children if(setsid() == -1) { printf("setsid failed\n"); assert(0); exit(-1); } umask(0); pid = fork(); //第二次fork if( pid != 0) exit(0); //second children chdir ("/"); for (int i = 0; i可以看到上面的代码里我fork了两次,虽然说这并不是必须的,但是这的确是对守护进程做出了一些更优化的操作。首先第一次fork:这里第一次fork的作用就是让shell认为这条命令已经终止,不用挂在终端输入上;再一个是为了后面的setsid服务,因为调用setsid函数的进程不能是进程组组长(会报错Operation not permitted),如果不fork子进程,那么此时的父进程是进程组组长,无法调用setsid。所以到这里子进程便成为了一个新会话组的组长。第二次fork:第二次fork是为了避免后期进程误操作而再次打开终端。因为打开一个控制终端的前提条件是该进程必须为会话组组长,而我们通过第二次fork,确保了第二次fork出来的子进程不会是会话组组长。下面罗列一下控制终端会产生哪些信号。程序中只要处理好这些信号,同样能达到上面函数实现的目的。//后台进程读取/写入终端输入产生下面两个信号,或者控制终端不存在情况读取和写入会产生 signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN);12//按CTRL-C ,CTRL-\ CTRL-Z会向前台进程组发送下面这些信号 signal(SIGINT, SIG_IGN ); signal(SIGQUIT, SIG_IGN ); signal(SIGTSTP, SIG_IGN );123//终端断开,会给会话组长或孤儿进程组所有成员发送下面信号 signal(SIGHUP, SIG_IGN );1还有有些信号也可以由终端shell产生,需要关注 signal(SIGCONT, SIG_IGN ); signal(SIGSTOP, SIG_IGN );12上面这些信号,应该有些程序缺省处理(SIG_DFL)本身动作就是忽略(SIG_IGN),不是退出进程。不过按照上面写也不会造成什么问题。至此关于Linux系统守护进程的具体 内容分享完毕,欢迎大家在评论区留言。以上就是良许教程网为各位朋友分享的Linux系统相关内容。想要了解更多Linux相关知识记得关注公众号"良许Linux",或扫描下方二维码进行关注,更多干货等着你!
关于"Linux系统守护进程怎么理解"就介绍到这了,更多相关内容可以搜索以前的文章,希望能够帮助大家答疑解惑,请多多支持网站!