`
sealbird
  • 浏览: 586725 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

setsid()

阅读更多
setsid() 
引用
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进 程。 Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。 比如,作业规划进程crond,打印进程lpd等。

守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同 Unix环境下守护进程的编程规则并不一致。需要注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将给出Linux下守护进程的编程要点和详细实例。

一. 守护进程及其特性

守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环 境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下 来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还 可以由用户终端(通常是 shell)执行。

总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果对进程有比较深入的认识就更容易理解和编程了。

二. 守护进程的编程要点

前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则 就是要满足守护进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下;

1. 在后台运行。

为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。

if(pid=fork())exit(0); //是父进程,结束父进程,子进程继续
2. 脱离控制终端,登录会话和进程组

有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长:

setsid();

说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

3. 禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

if(pid=fork()) exit(0); //结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

4. 关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们:

for(i=0;i 关闭打开的文件描述符close(i);>

5. 改变当前工作目录

进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如 /tmpchdir("/")

6. 重设文件创建掩模

进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0);

7. 处理SIGCHLD信号

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结 束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

signal(SIGCHLD,SIG_IGN);

这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

三. 守护进程实例

守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。

1. init.c清单

#include < unistd.h >#include < signal.h >#include < sys/param.h >#include < sys/types.h >#include < sys/stat.h >void init_daemon(void){int pid;int i;if(pid=fork())exit(0);//是父进程,结束父进程else if(pid< 0)exit(1);//fork失败,退出//是第一子进程,后台继续执行setsid();//第一子进程成为新的会话组长和进程组长//并与控制终端分离if(pid=fork())exit(0);//是第一子进程,结束第一子进程else if(pid< 0)exit(1);//fork失败,退出//是第二子进程,继续//第二子进程不再是会话组长for(i=0;i< NOFILE;++i)//关闭打开的文件描述符close(i);chdir("/tmp");//改变工作目录到/tmpumask(0);//重设文件创建掩模return;}
2. test.c清单

#include < stdio.h >#include < time.h >void init_daemon(void);//守护进程初始化函数main(){FILE *fp;time_t t;init_daemon();//初始化为Daemonwhile(1)//每隔一分钟向test.log报告运行状态{sleep(60);//睡眠一分钟if((fp=fopen("test.log","a")) >=0){t=time(0);fprintf(fp,"Im here at %sn",asctime(localtime(&t)) );fclose(fp);}}}
以上程序在RedHat Linux6.0下编译通过。步骤如下:

编译:gcc -g -o test init.c test.c

执行:./test

查看进程:ps -ef

从输出可以发现test守护进程的各种特性满足上面的要求。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tdonald/archive/2007/08/03/1724996.aspx
分享到:
评论

相关推荐

    nohup、&、setsid、fork和fg、bg究竟有啥区别?

    子进程如果要脱离这些,代码中可通过调用setsid来实现。,而命令行或脚本中可以通过使用命令setsid来运行程序实现。setsid帮助一个进程脱离从父进程继承而来的已打开的终端、隶属进程组和隶属的会话。  需要注意,...

    setsid,可以支撑centos7 的具备-w命令的程序

    更新更改时出错: setsid: invalid option -- 'w' Usage: setsid [options] [arguments ...] Options: -c, --ctty set the controlling terminal to the current one -h, --help display this help and exit -V, --...

    setsid-macosx:macosx 的 setsid

    macosx 的 setsid util-linux setsid命令的 MacOS X 端口。 概要 setsid program [arg...] 描述 setsid在新会话中运行程序。 选项 选项 描述 -w, --wait 等待程序执行结束,将child的退出值作为setsid返回值返回 ...

    Linux C api参考手册

    * setsid(): 设置会话 ID * system(): 执行外部命令 * wait(): 等待进程结束 * waitpid(): 等待进程结束 格式化输入输出篇 * fprintf(): 写入文件格式化字符串 * fscanf(): 读取文件格式化字符串 * printf(): 写入...

    PHP将进程作为守护进程的方法

    分享给大家供大家参考。具体分析如下: php中posix_setsid()的用法 文档解释是“Make the current process a session ...2 在子进程posix_setsid() 3 退出父进程 文档中有这么个例子: &lt;?php $pid = pcntl_fork();

    Linux技巧:让进程后台运行

    这些方法包括使用 nohup、setsid 以及 & 井号符号来让进程忽略 HUP 信号,从而避免中途失败。 1. nohup nohup 是我们首先想到的办法。顾名思义,nohup 的用途就是让提交的命令忽略 hangup 信号。nohup 的使用是...

    linux内核 0.11版本源码 带中文注释

    │ setsid.c │ string.c │ wait.c │ write.c │ _exit.c │ ├─mm │ Makefile │ memory.c │ page.s │ └─tools build.c 样例 main。c 用sourceinsight软件阅读 很方便 /* * linux/init/main.c * * (C) ...

    进程组和会话期1

    如果进程已经是某个进程组的组长,`setsid`将返回错误,因此通常会在`fork`后让父进程退出,子进程继续执行并调用`setsid`。 `setsid`函数的主要作用包括: 1. 使进程脱离原有的会话,不再受会话首进程的影响。 2. ...

    php实现 master-worker 守护多进程模式的实例代码

    - master进程调用`posix_setsid()`函数创建一个新的会话,使得它成为会话组长,避免被终端信号影响。 - master进程循环调用`runWorker()`创建并管理worker进程。 2. **子进程(Worker Process)**: - `...

    远程客户机断开连接后,linux服务器持续运行

    综上所述,Linux提供了多种方法来确保进程在远程客户端断开连接后仍能持续运行,包括 `nohup`、`setsid`、`screen` 和 `tmux`。这些工具和命令可以帮助你在执行需要长时间运行的任务时避免因网络不稳定或其他原因...

    补丁 重视Linux内核的安全漏洞.pdf

    在执行setsid0时,由于没有适当的同步机制,可能导致并发操作时出现竞态条件,进而影响系统的正常运行,比如造成程序崩溃或数据错误。 【应对策略与补丁】 对于上述提到的安全漏洞,开发者和系统管理员应保持对...

    linux守护进程

    2. 子进程调用 setsid() 函数创建一个新的会话期,父进程退出。 3. 忽略 SIGHUP 信号,再次 fork() 一个子进程。 4. 关闭所有文件描述符。 5. 消除 umask 影响。 6. 修改守护进程的当前工作目录。 7. 重新定位标准 I...

    C语言编写linux下的守护进程

    在上面的代码中,我们使用了 fork 函数来创建子进程,并使用 setsid 函数来使子进程成为新的会话组长和进程组长。然后,我们使用 close 函数来关闭打开的文件描述符,使用 chdir 函数来改变工作目录,并使用 umask ...

    隔几秒检测程序是否运行.zip_daemon_linux_进程守护

    3. **设置会话领导权**:通过调用`setsid()`函数,守护进程可以成为新的会话领导,进一步确保它不与任何终端关联。 4. **处理信号**:守护进程应正确处理各种信号,如SIGCHLD(子进程终止)、SIGHUP(挂断)等,以...

    Linux 守护进程

    2. **调用`setsid()`函数**:在第一个`fork()`之后,调用`setsid()`函数使子进程成为一个新的会话领导者,同时成为一个新的进程组领导者,这样可以确保进程独立于任何控制终端运行。 ```c setsid(); ``` 3. **...

    Linux系统中守护进程的创建方法.pdf

    fork 函数创建一个新进程,而 setsid 函数将进程从其父进程中分离出来,使其成为一个独立的会话期。同时,守护进程也可以使用其他编程语言来实现,如 Python、Java 等。 Linux 系统中守护进程的创建方法对系统的...

    c++ linux 守护进程

    1. **分离会话**:使用`setsid()`函数创建一个新的会话,这样进程就不再是终端的一部分。 2. **改变工作目录**:使用`chdir("/")`确保工作目录为根目录。 3. **关闭文件描述符**:使用`close(0)`、`close(1)`和`...

    Linux守护进程的编程方法.pdf

    - 为了避免守护进程受到控制终端的影响,需要通过调用`setsid()`函数使其成为一个新的会话组长。 - 示例代码: ```c if (setsid() ) { perror("setsid failed"); exit(1); } ``` 3. **禁止重新打开控制终端...

    daemon 程序例子daemon 程序例子

    1. **分离会话和控制终端**:首先,守护进程需要脱离与终端的关联,这可以通过调用`setsid()`函数实现。`setsid()`创建一个新的会话,并使进程成为该会话的首进程,同时不再属于任何终端。 2. **改变工作目录**:...

    进程同步.docx

    调用 setsid 函数后,进程成为新会话的组长进程和新进程组的组长进程,同时进程失去控制终端。 4. 控制终端 会话的组长进程打开一个终端之后,该终端就成为该会话的控制终端。与控制终端建立连接的组长进程成为...

Global site tag (gtag.js) - Google Analytics