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都行) 可以看到现在运行着两个 ...
随机推荐
- Adobe photoshop CS5(32位and64位)破解补丁
转载自:http://www.wusiwei.com 网上有很多photoshop cs5的永久序列号,但这个在2年前还能有用,现在一般都不行,序列号给你验证过了,然后过几秒钟还是会弹出要你输入序列号 ...
- centos7 彻底卸载PHP7
[root@xxx php-memcached]# rpm -qa | grep php php70w-common--.w7.x86_64 php70w-devel--.w7.x86_64 php7 ...
- SqlParameter的两种用法【二】
private void Loadprovince() { string sql = "select * from Tables where ArealdPid=@pid"; /第 ...
- AFM(3)---Maude使用说明
load file-name 1可用绝对路径 2.可进入maude文件所在目录下load 3.默认工作空间是什么?
- Linux运维人员最常用 150 个命令汇总
linux 命令是对 Linux 系统进行管理的命令.对于 Linux 系统来说,无论是中央处理器.内存.磁盘驱动器.键盘.鼠标,还是用户等都是文件, Linux 系统管理的命令是它正常运行的核心,与 ...
- 在选择列表中无效,因为该列既不包含在聚合函数中,也不包含在 GROUP BY 子句
在选择列表中无效,因为该列既不包含在聚合函数中,也不包含在 GROUP BY 子句 突然看到这个问题,脑袋一蒙,不知道啥意思,后来想想,试图把select里的选项放到后面,问题自然解决! 下面这 ...
- Android 通过 JNI 访问 Java 字段和方法调用
在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型.字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系. 有了之前那些基础,就可以实现 Jav ...
- 在线html编辑器
1.http://liveweave.com/ 2.有时间研究下这个. http://dabblet.com/gist/4034534 3.10个免费的在线编辑器. https://www.ev这个需 ...
- HTML5-用canvas画布rotate字体旋转(中国象棋棋谱)。
一开始我们老师安排我做这个作业,在这个作业我遇到了一个很重大的问题就是,文字旋转这么旋转,我查了很多资料. 1发现绘画正方形,使他正方形中心原点旋转非常容易理解.(我相信这个很多人看一下都会懂,) 1 ...
- python中的面向对象学习以及类的多态
接下来类的第三个重要的特性:多态(一种接口,多种实现) 多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特 ...