Linux 下Qt实现守护进程实例(转)
- MySignal(SIGTTOU, SIG_IGN);
- MySignal(SIGTTIN, SIG_IGN);
- MySignal(SIGTSTP, SIG_IGN);
- MySignal(SIGHUP, SIG_IGN);
- MySignal(SIGCHLD,SIG_IGN);
- pid = fork();
- if (pid > 0) //父进程终止;子进程继续运行
- exit(0);
- setsid();
- pid = fork();
- if (pid > 0) //子进程终止;孙进程继续运行,孙进程不在是会话组长
- exit(0);
- umask(0);
- fdTableSize = getdtablesize();
- for (fd=0; fd<fdTableSize; fd++)
- close(fd);
- chdir("/");
- RedirectStdIO("/dev/null", LOG_FILE, LOG_FILE); //重定向标准输入输出
- fdTableSize = getdtablesize();
- for (fd=3; fd<fdTableSize; fd++)
- close(fd);
- bool AlreadyRunning()
- {
- int fdLockFile;
- char szPid[32];
- struct flock fl;
- /* 打开锁文件 */
- fdLockFile = open(LOCK_FILE, O_RDWR | O_CREAT, LOCK_FILE_MODE);
- if (fdLockFile < 0)
- {
- ErrorLog("AlreadyRunning open");
- exit(EXIT_FAILURE);
- }
- /*对整个锁文件加写锁 */
- fl.l_type = F_WRLCK; //记录锁类型:独占性写锁
- fl.l_whence = SEEK_SET; //加锁区域起点:距文件开始处l_start个字节
- fl.l_start = 0;
- fl.l_len = 0; //加锁区域终点:0表示加锁区域自起点开始直至文件最大可能偏移量为止,不管写入多少字节在文件末尾,都属于加锁范围
- if (fcntl(fdLockFile, F_SETLK, &fl) < 0)
- {
- if (EACCES == errno || EAGAIN == errno) //系统中已有该守护进程的实例在运行
- {
- close(fdLockFile);
- return true;
- }
- ErrorLog("AlreadyRunning fcntl");
- exit(EXIT_FAILURE);
- }
- /* 清空锁文件,然后将当前守护进程pid写入锁文件 */
- ftruncate(fdLockFile, 0);
- sprintf(szPid, "%ld", (long)getpid());
- write(fdLockFile, szPid, strlen(szPid) + 1);
- return false;
- }
1./*
2. * test.c
3. *
4. * Created on: 2011-04-23
5. * Author: lingdxuyan
6. */
7.
8.
9. #include <stdio.h> /* 标准输入输出定义 */
10. #include <stdlib.h> /* 标准函数库定义 */
11. #include <unistd.h> /* Unix 标准函数定义 */
12. #include <sys/types.h>
13. #include <sys/stat.h>
14. #include <sys/wait.h>
15. #include <fcntl.h> /* 文件控制定义 */
16. #include <errno.h> /* 错误号定义 */
17. #include <signal.h> /* 信号定义 */
18. #include <time.h> /* 定时器定义 */
19. #include <stdarg.h> /* 可变参数定义 */
20. #include <syslog.h> /* syslog定义 */
21. #include <string.h>
22. #include <fcntl.h>
23.
24. #define true 1
25. #define false 0
26.
27. typedef unsigned char BYTE;
28. typedef BYTE bool;
29. typedef BYTE byte;
30.
31. #define MAX_BUF_SIZE 1024
32.
33. #define CONFIG_FILE "/etc/daemon.conf"
34. #define LOG_FILE "/tmp/daemon.log"
35. #define LOCK_FILE "/var/run/daemon.pid"
36. #define LOCK_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
37.
38.
39.static volatile sig_atomic_t g_nUpdateParameter = 1;
40.static volatile sig_atomic_t g_nServer = 0;
41.//static volatile int g_nUpdateParameter = 1;
42.//static volatile int g_nServer = 0;
43.
44.
45. /*
46. * 功能: 写日志
47. */
48. void vWriteLog(int nPriority, const char *fmt, va_list va)
49. {
50. #ifdef USE_SYSLOG
51. vsyslog(LOG_DAEMON | nPriority, fmt, va);
52. #else
53. FILE *stream;
54. if (nPriority & LOG_ERR)
55. stream = stderr;
56. else
57. stream = stdout;
58. vfprintf(stream, fmt, va);
59. fflush(stream);
60. #endif
61. }
62. void WriteLog(int nPriority, const char *fmt, ...)
63. {
64. va_list va;
65.
66. va_start(va, fmt);
67. vWriteLog(nPriority, fmt, va);
68. va_end(va);
69. }
70.
71. /*
72. * 功能: 写错误日志,用法类似perror
73. */
74. void ErrorLog(const char *str)
75. {
76. WriteLog(LOG_ERR, "%s: %s\n", str, strerror(errno));
77. }
78. /*
79. * 功能: 写错误日志,用法类似于printf
80. */
81. void ErrorLogFmt(const char *fmt, ...)
82. {
83. va_list va;
84.
85. va_start(va, fmt);
86. vWriteLog(LOG_ERR, fmt, va);
87. va_end(va);
88. }
89.
90. /*
91. * 功能: 写日志,用法类似printf
92. */
93. void InfoLog(const char *fmt, ...)
94. {
95. va_list va;
96.
97. va_start(va, fmt);
98. vWriteLog(LOG_INFO, fmt, va);
99. va_end(va);
100. }
101.
102. /*
103. * 功能: 重定向标准输入输出
104. */
105. void RedirectStdIO(char *szInFile, char *szOutFile, char *szErrFile)
106. {
107. int fd;
108.
109. if (NULL != szInFile)
110. {
111. fd = open(szInFile, O_RDONLY | O_CREAT, 0666);
112. if (fd > 0)
113. {
114. // 标准输入重定向
115. if (dup2(fd, STDIN_FILENO) < 0)
116. {
117. ErrorLog("RedirectStdIO dup2 in");
118. exit(EXIT_FAILURE);
119. }
120.
121. close(fd);
122. }
123. else
124. ErrorLogFmt("RedirectStdIO open %s: %s\n", szInFile, strerror(errno));
125. }
126.
127. if (NULL != szOutFile)
128. {
129. fd = open(szOutFile, O_WRONLY | O_CREAT | O_APPEND /*| O_TRUNC*/, 0666);
130. if (fd > 0)
131. {
132. // 标准输出重定向
133. if (dup2(fd, STDOUT_FILENO) < 0)
134. {
135. ErrorLog("RedirectStdIO dup2 out");
136. exit(EXIT_FAILURE);
137. }
138.
139. close(fd);
140. }
141. else
142. ErrorLogFmt("RedirectStdIO open %s: %s\n", szOutFile, strerror(errno));
143. }
144.
145. if (NULL != szErrFile)
146. {
147. fd = open(szErrFile, O_WRONLY | O_CREAT | O_APPEND /*| O_TRUNC*/, 0666);
148. if (fd > 0)
149. {
150. // 标准错误重定向
151. if (dup2(fd, STDERR_FILENO) < 0)
152. {
153. ErrorLog("RedirectIO dup2 error");
154. exit(EXIT_FAILURE);
155. }
156.
157. close(fd);
158. }
159. else
160. ErrorLogFmt("RedirectStdIO open %s: %s\n", szErrFile, strerror(errno));
161. }
162. }
163.
164. /*
165. * 功能: 读取配置文件SIGHUP信号处理函数
166. */
167. void UpdateHandler(int nSigNum)
168. {
169. g_nUpdateParameter = 1;
170. }
171.
172. /*
173. * 功能: 折行服务SIG_USR1信号处理函数
174. */
175. void ServerHandler(int nSigNum)
176. {
177. g_nServer = 1;
178. }
179.
180. /*
181. * 功能:确保任一时刻系统中只有一个该守护进程实例在运行
182. */
183. bool AlreadyRunning()
184. {
185. int fdLockFile;
186. char szPid[32];
187. struct flock fl;
188.
189. /* 打开锁文件 */
190. fdLockFile = open(LOCK_FILE, O_RDWR | O_CREAT, LOCK_FILE_MODE);
191. if (fdLockFile < 0)
192. {
193. ErrorLog("AlreadyRunning open");
194. exit(EXIT_FAILURE);
195. }
196.
197. /*对整个锁文件加写锁 */
198. fl.l_type = F_WRLCK; //记录锁类型:独占性写锁
199. fl.l_whence = SEEK_SET; //加锁区域起点:距文件开始处l_start个字节
200. fl.l_start = 0;
201. fl.l_len = 0; //加锁区域终点:0表示加锁区域自起点开始直至文件最大可能偏移量为止,不管写入多少字节在文件末尾,都属于加锁范围
202. if (fcntl(fdLockFile, F_SETLK, &fl) < 0)
203. {
204. if (EACCES == errno || EAGAIN == errno) //系统中已有该守护进程的实例在运行
205. {
206. close(fdLockFile);
207. return true;
208. }
209.
210. ErrorLog("AlreadyRunning fcntl");
211. exit(EXIT_FAILURE);
212. }
213.
214. /* 清空锁文件,然后将当前守护进程pid写入锁文件 */
215. ftruncate(fdLockFile, 0);
216. sprintf(szPid, "%ld", (long)getpid());
217. write(fdLockFile, szPid, strlen(szPid) + 1);
218.
219. return false;
220. }
221.
222. /*
223. * 功能:设置信号nSigNum的处理函数为handler,在调用该信号处理函数前.若handler不为SIG_DEF或SIG_IGN,则系统会将该信号添加到信号屏蔽字中;信号处理函数返回后,信号屏蔽字恢复到原先值.这样,可保证在处理指定信号时,如果该信号再次发生,那么它会被阻塞到上一信号处理结束为止.不过,要是此时信号发生了多次,在对该信号解除阻塞后,也只会调用一次信号处理函数
224. */
225. typedef void (*sighandler)(int);
226. sighandler MySignal(int nSigNum, sighandler handler)
227. //void ( *Signal(int nSigNum, void (*handler)(int)) )(int)
228. {
229. struct sigaction saNew, saOld;
230.
231. saNew.sa_handler = handler;
232. sigemptyset(&saNew.sa_mask);
233. if (SIG_DFL != handler && SIG_IGN != handler)
234. sigaddset(&saNew.sa_mask, nSigNum);
235.
236. saNew.sa_flags = 0;
237. if (SIGALRM == nSigNum)
238. {
239. //不重启该信号中断的系统调用
240. #ifdef SA_INTERRUPT
241. saNew.sa_flags |= SA_INTERRUPT;
242. #endif
243. }
244. else
245. {
246. //重启该信号中断的系统调用
247. #ifdef SA_RESTART
248. saNew.sa_flags |= SA_RESTART;
249. #endif
250. }
251.
252. if (sigaction(nSigNum, &saNew, &saOld) < 0)
253. return SIG_ERR;
254.
255. return saOld.sa_handler;
256. }
257.
258. /*
259. * 功能: 将普通进程改造成守护进程
260. */
261. void InitDaemon()
262. {
263. pid_t pid;
264. int fd, fdTableSize;
265.
266. /* 1、屏蔽控制终端操作信号
267. */
268. MySignal(SIGTTOU, SIG_IGN);
269. MySignal(SIGTTIN, SIG_IGN);
270. MySignal(SIGTSTP, SIG_IGN);
271. MySignal(SIGHUP, SIG_IGN);
272.
273. /* 2、忽略子进程结束信号
274. */
275. #ifdef IGN_SIGCHLD
276. signal(SIGCHLD, SIG_IGN); //忽略子进程结束信号,避免僵死进程产生
277. #endif
278.
279. /* 3、使守护进程后台运行
280. * 父进程直接退出,子进程继续运行(让守护进程在子进程中后台运行)
281. */
282. pid = fork();
283. if (pid > 0) //父进程终止运行;子进程过继给init进程,其退出状态也由init进程处理,避免了产生僵死进程
284. exit(EXIT_SUCCESS);
285. else if (pid < 0)
286. {
287. ErrorLog("InitDaemon fork(parent)");
288. exit(EXIT_FAILURE);
289. }
290.
291. /* 4、脱离控制终端,登录会话和进程组
292. * 调用setsid()使子进程成为会话组长
293. */
294. setsid();
295.
296. /* 5、禁止进程重新打开控制终端
297. * 通过使守护进程不再成为会话组长来禁止进程重新打开控制终端
298. */
299. pid = fork();
300. if (pid > 0) //子进程终止运行;孙进程过继给init进程,其退出状态也由init进程处理,避免了产生僵死进程
301. exit(EXIT_SUCCESS);
302. else if (pid < 0)
303. {
304. ErrorLog("InitDaemon fork(child)");
305. exit(EXIT_FAILURE);
306. }
307.
308. /* 6、重设文件创建掩模
309. */
310. umask(0);
311.
312. /* 7、关闭打开的文件描述符
313. */
314. RedirectStdIO("/dev/null", LOG_FILE, LOG_FILE); //重定向标准输入输出
315. fdTableSize = getdtablesize();
316. for (fd=3; fd<fdTableSize; fd++)
317. close(fd);
318.
319. /* 8、改变当前工作目录
320. */
321. chdir("/tmp");
322. }
323.
324. /*
325. * 功能: 读取守护进程的配置文件,并将获取到的信息保存在szParameter中
326. */
327. void ReadConfigFile(char *szParameter)
328. {
329. FILE *stream;
330. int nRet;
331.
332. InfoLog("------ ReadConfigFile ------\n");
333. stream = fopen(CONFIG_FILE, "r");
334. if (NULL != stream)
335. {
336. nRet = fread(szParameter, sizeof(char), MAX_BUF_SIZE, stream);
337. if (nRet >= 0)
338. szParameter[nRet - 1] = '\0';
339. fclose(stream);
340. InfoLog("ReadConfigFile sucesss!\n");
341. }
342. else
343. ErrorLogFmt("ReadConfigFile fopen %s: %s\n", CONFIG_FILE, strerror(errno));
344. }
345.
346. /*
347. * 功能: 执行守护进程的服务,也就是将szParameter用echo打印出来
348. */
349. void Server(char *szParameter)
350. {
351. int nStatus;
352. pid_t pid;
353.
354. InfoLog("------ Server ------\n");
355.
356. pid = vfork(); //生成子进程
357. #ifdef IGN_SIGCHLD
358. InfoLog("ignore child SIGCHLD signal!\n");
359. if (0 == pid) //子进程
360. {
361. if (execlp("echo", "echo", szParameter, NULL) < 0)
362. {
363. ErrorLog("Server execlp");
364. exit(EXIT_FAILURE);
365. }
366. }
367. else if (pid < 0)
368. {
369. ErrorLog("Server vfork(parent)");
370. }
371. #else
372. if (pid > 0) //父进程
373. {
374. waitpid(pid, &nStatus, 0); //等待子进程结束,否则子进程会成为僵死进程,一直存在,即便子进程已结束执行
375. }
376. else if (0 == pid) //子进程
377. {
378. pid = vfork(); //生成孙进程
379. if (pid > 0)
380. {
381. exit(EXIT_SUCCESS); //子进程退出,孙进程过继给init进程,其退出状态也由init进程处理,与原有父进程无关
382. }
383. else if (0 == pid) //孙进程
384. {
385. if (execlp("echo", "echo", szParameter, NULL) < 0)
386. {
387. ErrorLog("Server execlp");
388. exit(EXIT_FAILURE);
389. }
390. }
391. else
392. {
393. ErrorLog("Server vfork(child)");
394. }
395. }
396. else
397. {
398. ErrorLog("Server vfork(parent)");
399. }
400. #endif
401. }
402.
403. int main()
404. {
405. time_t t;
406. sigset_t sigNewMask, sigOldMask;
407. char szParameter[MAX_BUF_SIZE];
408.
409. //将普通进程改造成守护进程
410. InitDaemon();
411. if (AlreadyRunning()) //若系统中已有该守护进程的实例在运行,则退出
412. {
413. ErrorLogFmt("Daemon already running!\n");
414. exit(EXIT_FAILURE);
415. }
416.
417. //阻塞SIGHUP信号和SIGUSR1信号
418. sigemptyset(&sigNewMask);
419. sigaddset(&sigNewMask, SIGHUP);
420. sigaddset(&sigNewMask, SIGUSR1);
421. if (sigprocmask(SIG_BLOCK, &sigNewMask, &sigOldMask) < 0)
422. {
423. ErrorLog("main sigprocmask");
424. exit(EXIT_FAILURE);
425. }
426.
427. //为SIGHUP信号和SIGUSR1信号添加信号处理函数
428. MySignal(SIGHUP, UpdateHandler);
429. MySignal(SIGUSR1, ServerHandler);
430.
431. t = time(NULL);
432. InfoLog("Daemon %d start at %s", getpid(), ctime(&t));
433.
434. //读取守护进程配置文件
435. ReadConfigFile(szParameter);
436. while(1)
437. {
438. sigsuspend(&sigOldMask);//将进程的信号屏蔽字暂时替代为sigOldMask并挂起进程,直到捕捉到一个信号并从其信号处理函数返回,sigsuspend才返回并将信号屏蔽字恢复为调用它之前的值;若捕捉到的是终止进程信号,sigsuspend不返回,进程直接终止
439. if (1 == g_nUpdateParameter) //读取配置文件
440. {
441. ReadConfigFile(szParameter);
442. g_nUpdateParameter = 0;
443. }
444.
445. if (1 == g_nServer) //执行服务
446. {
447. Server(szParameter);
448. g_nServer = 0;
449. }
450. }
451.
452. return 0;
453. }
Linux 下Qt实现守护进程实例(转)的更多相关文章
- Linux下一个简单守护进程的实现 (Daemon)
在Linux/UNIX系统引导的时候会开启很多服务,这些服务称为守护进程(也叫Daemon进程).守护进程是脱离于控制终端并且在后台周期性地执行某种任务或等待处理某些事件的进程,脱离终端是为了避免进程 ...
- Linux下tomcat作为守护进程运行(开机启动、以指定的用户运行、解决非root身份不能绑定1024以下端口的问题)的配置方法
如题. 参考资料: http://www.jdiy.org/read.jd?id=y0haaynq1w http://blog.csdn.net/shw2004/article/details/578 ...
- Linux下简单的socket通信实例
Linux下简单的socket通信实例 If you spend too much time thinking about a thing, you’ll never get it done. —Br ...
- linux下C语言多线程编程实例
用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...
- Linux下查看某一进程所占用内存的方法
Linux下查看某一个进程所占用的内存,首先可以通过ps命令找到进程id,比如 ps -ef | grep kafka 可以看到kafka这个程序的进程id 可以看到是2913,现在可以使用如下命令查 ...
- Linux下Qt的安装与配置
参考资料:http://www.cnblogs.com/emouse/archive/2013/01/28/2880142.html Linux 下编译.安装.配置 QT 下载qt 这里用的是4.7. ...
- Linux 下监控用户最大进程数参数(nproc)是否到达上限
Linux 下监控用户最大进程数参数(nproc)是否到达上限的步骤: 1.查看各系统用户的进程(LWP)数: 注意:默认情况下采用 ps 命令并不能显示出所有的进程.因为 Linux 环境下执行多线 ...
- Linux编程之《守护进程》
Intro ----- 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常 ...
- Linux下Tomcat端口、进程以及防火墙设置
Linux下Tomcat端口.进程以及防火墙设置 1,查看tomcat进程: #ps -aux | grep tomcat(或者ps -ef | grep tomcat都行) 可以看到现在运行着两个 ...
随机推荐
- Js操作Cookie的实现
- 设计模式(五)Builder Pattern建造者模式
在我们日常生活中,如构建一个飞船,一个手机,一栋建筑,都会有非常复杂的组装,这时候应该用到建造者模式 以建造一个飞船为例 案例:造小页飞船 1.飞船各部分元件 package com.littlepa ...
- Django 日志
Django使用Python内置的logging模块实现它自己的日志系统. 如果你没有使用过logging模块,请参考Python教程中的相关章节. 直达链接<logging模块详解>. ...
- 结合CRT与欧拉定理高阶幂求余
- 《剑指offer》第五十八题(翻转单词顺序)
// 面试题58(一):翻转单词顺序 // 题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变. // 为简单起见,标点符号和普通字母一样处理.例如输入字符串"I am a ...
- 《剑指offer》第四十七题(礼物的最大价值)
// 面试题47:礼物的最大价值 // 题目:在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值 // (价值大于0).你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或 // 者向下 ...
- axios写法
- Python Selenium unittest+HTMLTestRunner实现 自动化测试及发送测试报告邮件
1.UI测试框架搭建-目录结构 2. 文件介绍 2.1.baseinfo->__init__.py 配置文件定义基础参数 #-*-coding:utf-8-*- #测试用例配置参数 base_u ...
- 配置java环境jdk
最近尝试改公司的项目中的一个后台管理系统,前后台都让我一个做,所以要配置一下java环境: 1. 按装jdk 1.6//2. 安装eclipse3. 安装maven4. 安装eclispe的maven ...
- js实现文件的上传和输出,拖拽上传图片
js文件上传 文件下载 以前的文件的下载都是在服务器,现在也是放在服务器比较好,有时候为了一些开发的方便,我们临时把处理的数据就放在了本地,然后自己访问.这个也是可以的. 1.利用html5的 Fil ...