Unix环境高级编程(十四)守护进程实现时间服务器
守护进程是在后台运行不受终端控制的进程(如输入、输出等),一般的网络服务都是以守护进程的方式运行。守护进程脱离终端的主要原因有两点:(1)用来启动守护进程的终端在启动守护进程之后,需要执行其他任务。(2)(如其他用户登录该终端后,以前的守护进程的错误信息不应出现)由终端上的一些键所产生的信号(如中断信号),不应对以前从该终端上启动的任何守护进程造成影响。要注意守护进程与后台运行程序(即加&启动的程序)的区别。
创建守护进程的过程:
1. 调用fork创建子进程。父进程终止,让子进程在后台继续执行。
2. 子进程调用setsid产生新会话期并失去控制终端调用setsid()使子进程进程成为新会话组长和新的进程组长,同时失去控制终端。
3. 忽略SIGHUP信号。会话组长进程终止会向其他进程发该信号,造成其他进程终止。
4. 调用fork再创建子进程。子进程终止,子子进程继续执行,由于子子进程不再是会话组长,从而禁止进程重新打开控制终端。
5. 改变当前工作目录为根目录。一般将工作目录改变到根目录,这样进程的启动目录也可以被卸掉。
6. 关闭打开的文件描述符,打开一个空设备,并复制到标准输出和标准错误上。 避免调用的一些库函数依然向屏幕输出信息。
7. 重设文件创建掩码清除从父进程那里继承来的文件创建掩码,设为0。
8. 用openlog函数建立与syslogd的连接。
创建守护进程的例子如下程序所示:
void daemon_init(const char* pname,int facility)
{
int i;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/* 清除文件模式创建掩码,使新文件的权限位不受原先文件模式创建掩码的权限位的影响*/
umask(0);
if(getrlimit(RLIMIT_NOFILE,&rl) < 0)
{
perror("getrlimit() error");
exit(-1);
}
if((pid = fork()) < 0)
{
perror("fork() error");
exit(-1);
}
else if(pid > 0) /*父进程终止 */
exit(0);
setsid(); /* 子进程成为会话首进程*/
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if(sigaction(SIGHUP,&sa,NULL) < 0)
{
perror("sigaction() error");
exit(-1);
}
if((pid = fork()) < 0)
{
perror("fork() error");
exit(-1);
}
else if(pid > 0)
exit(0); /* 第一个子程进终止,保证后面操作不会分配终端 */
if(chdir("/")<0) /* 改变工作目录 */
{
perror("chdir() error");
exit(-1);
}
if(rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for(i=0;i<rl.rlim_max;++i) /*关闭所有打开的文件描述字*/
close(i);
openlog(pname, LOG_PID, facility); /*用syslogd处理错误*/
}
现在要用守护进程实现一个时间服务器,呈现的功能是:服务器运行后自动成为守护进程,返回shell;客户端运行后收到服务器发来的当前时间。
时间服务器程序(timeserver.c)如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <syslog.h>
10 #include <sys/resource.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <time.h>
15
16 #define MAXLINE 100
17
18 void daemon_init(const char* pname,int facility)
19 {
20 int i;
21 pid_t pid;
22 struct rlimit rl;
23 struct sigaction sa;
24 /* 清除文件模式创建掩码,使新文件的权限位不受原先文件模式创建掩码的权限位的影响*/
25 umask(0);
26 if(getrlimit(RLIMIT_NOFILE,&rl) < 0)
27 {
28 perror("getrlimit() error");
29 exit(-1);
30 }
31 if((pid = fork()) < 0)
32 {
33 perror("fork() error");
34 exit(-1);
35 }
36 else if(pid > 0) /*父进程终止 */
37 exit(0);
38 setsid(); /* 子进程成为会话首进程*/
39 sa.sa_handler = SIG_IGN;
40 sigemptyset(&sa.sa_mask);
41 sa.sa_flags = 0;
42 if(sigaction(SIGHUP,&sa,NULL) < 0)
43 {
44 perror("sigaction() error");
45 exit(-1);
46 }
47 if((pid = fork()) < 0)
48 {
49 perror("fork() error");
50 exit(-1);
51 }
52 else if(pid > 0)
53 exit(0); /* 第一个子程进终止,保证后面操作不会分配终端 */
54 if(chdir("/")<0) /* 改变工作目录 */
55 {
56 perror("chdir() error");
57 exit(-1);
58 }
59 if(rl.rlim_max == RLIM_INFINITY)
60 rl.rlim_max = 1024;
61 for(i=0;i<rl.rlim_max;++i) /*关闭所有打开的文件描述字*/
62 close(i);
63 openlog(pname, LOG_PID, facility); /*用syslogd处理错误*/
64 }
65
66 int main(int argc,char *argv[])
67 {
68 int listenfd, connfd;
69 socklen_t addrlen, len;
70 struct sockaddr cliaddr;
71 struct sockaddr_in server;
72 char buff[MAXLINE];
73 time_t ticks;
74 int n;
75 bzero(&server, sizeof(server));
76 bzero(&cliaddr,sizeof(cliaddr));
77 server.sin_family = AF_INET;
78 server.sin_port = htons(5050);
79 server.sin_addr.s_addr = htonl(INADDR_ANY);
80 daemon_init(argv[0], 0);
81 if((listenfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
82 {
83 syslog(LOG_NOTICE|LOG_LOCAL0,"socket error");
84 exit(-1);
85 }
86 if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1)
87 {
88 syslog(LOG_NOTICE|LOG_LOCAL0,"socket error");
89 exit(-1);
90 }
91 if(listen(listenfd,5)==-1)
92 {
93 syslog(LOG_NOTICE|LOG_LOCAL0,"listen error");
94 exit(-1);
95 }
96 for ( ; ; )
97 {
98 len = sizeof(cliaddr);
99 connfd = accept(listenfd,&cliaddr, &len);
100 ticks = time(NULL);
101 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
102 if((n= write(connfd, buff, strlen(buff)))==-1)
103 syslog(LOG_NOTICE|LOG_LOCAL0,"write error");
104 close(connfd);
105 }
106 }
客户端程序(timeclient.c)如下:
1 #include <unistd.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <netdb.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #define PORT 5050
9 #define MAXDATASIZE 100
10
11 int main(int argc, char *argv[])
12 {
13 int fd, numbytes;
14 char buf[MAXDATASIZE];
15 struct sockaddr_in server;
16 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
17 {
18 perror("Create socket failed.");
19 exit(-1);
20 }
21 bzero(&server, sizeof(server));
22 server.sin_family = AF_INET;
23 server.sin_port = htons(PORT);
24 server.sin_addr.s_addr = htonl(INADDR_ANY);
25 if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
26 {
27 perror("connect failed.");
28 exit(-1);
29 }
30 if( ((numbytes = recv(fd, buf, MAXDATASIZE, 0)) == -1))
31 {
32 perror("recv error.");
33 exit(-1);
34 }
35 buf[numbytes] ='\0';
36 printf("Server Message: %s\n",buf);
37 close(fd);
38 }
程序运行过程: 先运行时间服务器程序,再在运行客户端程序。
运行时间服务器程序结果如下:
此时timeserver是个守护进程,已经在运行,通过ps -axj命令可以查看该进程,查看结果如下:
Unix环境高级编程(十四)守护进程实现时间服务器的更多相关文章
- UNIX环境高级编程——初始化一个守护进程
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h&g ...
- Unix环境高级编程(十八)高级进程间通信
本章主要介绍了基于STREAM的管道和UNIX域套接字,这些IPC可以在进程间传送打开文件描述符.服务进程可以使用它们的打开文件描述符与指定的名字相关联,客户进程可以使用这些名字与服务器进程通信. 1 ...
- UNIX环境高级编程 第8章 进程控制
本章是UNIX系统中进程控制原语,包括进程创建.执行新程序.进程终止,另外还会对进程的属性加以说明,包括进程ID.实际/有效用户ID. 进程标识 每个进程某一时刻在系统中都是独一无二的,它们之间是用一 ...
- UNIX环境高级编程 第7章 进程环境
本章涉及C/C++程序中main函数是如何被调用的.命令行参数如何传递给main函数.程序的内存空间布局.程序如何使用环境变量.程序如何终止退出. main函数 C程序或C++程序总是从main函数开 ...
- Unix环境高级编程(十二)线程控制
本章介绍了一个进程中多个线程之间如何保持数据的似有性及进程的系统调用如何与线程进行交互. 1.线程限制: Single Unix定义了一线线程操作的限制,和其他的限制一样,可以通过sysconf来查询 ...
- UNIX环境高级编程 第9章 进程关系
在第8章学习了进程的控制原语,通过各种进程原语可以对进程进行控制,包括新建进程.执行新程序.终止进程等.在使用fork( )产生新进程后,就出现了进程父子进程的概念,这是进程间的关系.本章更加详细地说 ...
- Unix环境高级编程(十五)高级I/O
1.非阻塞I/O 对低速设备的I/O操作可能会使进程永久阻塞,这类系统调用主要有如下情况:(1)如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道.终端设备和网络设备).(2)如果数据不能立 ...
- Unix环境高级编程(十)信号续
1.signal函数 Unix系统的信号机制最简单的接口是signal函数,函数原型如下: #include <signal.h> typedef void (*sighandler_t) ...
- unix环境高级编程第四章笔记
文件和目录 start fstart lstart函数 一旦给出pathname, start函数就返回了与此命名文件有关的信息结构 #include <sys/start> int st ...
随机推荐
- jQuery调用WCF需要注意的一些问题
昨天,博客园首页增加了Digg功能.在该功能中我们开始尝试使用jQuery直接调用WCF.之前我们采用的方案是jQuery调用Web Service,然后WebService再调用服务层.这样调用主要 ...
- 基于json的jquery地区联动探索
贴一个基于jquery联动的代码,相信这样的代码有一大把,就当是jquery的练手吧, 写这个东西的初衷是来之于新浪微博,在新浪微博帐号设置里面有个地区的选项,使用js写的,想把它的代码给截获下来,可 ...
- PCL学习笔记二:Registration (ICP算法)
原文:http://blog.csdn.net/u010696366/article/details/8941938 PCL Registration API Registration:不断调整,把不 ...
- 套间线程(apartment thread)模型和自由线程(free thread)模型互相创建的情况
- Nuget出现错误怎么办?
Go to the packages folder in the Windows Explorer and delete it. Open Visual Studio and Go to To ...
- 以Settings.APPLICATION_DEVELOPMENT_SETTINGS打开开发人员面板出错总结
近期遇到了一个问题,感觉须要记录一下. 要打开开发人员面板,之前的代码例如以下: Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVE ...
- 怎样增加Dave 英语学习小组
一. 增加小组 英语对IT 是非常重要的,但非常多人都不能坚持去学习,Dave 英语学习小组成立与已经超过半年,如今进行扩招.欢迎想提高英语,而且能够坚持每天学习的人,增加Dave 的小组.并 ...
- 使用Yii 1.1框架搭建第一个web应用程序
我已经安装好了WampServer,web项目根目录是 D:\wamp\www. 1.下载Yii 1.1的源码 yii-1.1.14.f0fee9.tar.gz: 2.解压源码包,放在web项目的根目 ...
- 【CSWS2014 Summer School】深度问答技术及其在搜索中的应用-马艳军
Title: 深度问答技术及其在搜索中的应用 马艳军博士, 百度 Abstract: 深度问答(DeepQA)是一种基于对自然语言深度理解的智能问答技术,其核心技术涉及知识图谱建设.语义表示和计算.语 ...
- Appium Python 五:元素定位
总结 单个元素定位: driver.find_element_by_accessibility_id(id) driver.find_element_by_android_uiautomator(ui ...