Linux 守护进程是 Linux 的后台服务进程,相当于 Windows 服务,对于为 Linux 开发服务程序的朋友来说,Linux 守护进程相关技术是必不可少的,因为这个技术不仅仅是为了开发守护进程,还可以拓展到多进程,父子进程文件描述符共享,父子进程通讯、控制等方面,是实现 Linux 大型服务的基础技术之一。
去年我也曾写了一篇关于守护进程的帖子,名字叫《.NET 跨平台实践:用 C# 开发 Linux 守护进程》,这篇文章的的确确实现了一个 Daemon,不过,它有一个弱点,不能运行多线程!
这篇帖子的目的就是进一步完善,让我们写出一个功能完整,可以用于生产环节的基本的守护进程。
先帖代码(假设项目名是 daemon):
- 1 using System;
- 2 using System.Threading;
- 3 using System.Timers;
- 4 using System.Runtime.InteropServices;
- 5 using System.IO;
- 6 using System.Text;
- 7
- 8
- 9 /********************************************
- 10 * 一个完整的linux daemon示例,作者宇内流云 *
- 11 ********************************************/
- 12
- 13 namespace daemon
- 14 {
- 15 class Program
- 16 {
- 17
- 18 const stringDaemonTag ="--daemon.";
- 19 static voidMain(string[] args)
- 20 {
- 21 // 判断是否已经进入Daemon状态,如果是,就直接执行后台主函数
- 22 if(string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DaemonTag)) ==false)
- 23 {
- 24Environment.SetEnvironmentVariable(DaemonTag,null);
- 25 DaemonMain(args);
- 26 return;
- 27 }
- 28
- 29
- 30 // 如果还没有进入daemon状态,就作daemon处理
- 31 /////////////////////////////////////////////////////
- 32
- 33 intpid = fork();
- 34 if(pid !=0) exit(0);
- 35 setsid();
- 36pid = fork();
- 37 if(pid !=0) exit(0);
- 38umask(0);
- 39
- 40
- 41 // 这儿已经进入"守护进程"工作状态了!
- 42
- 43 // 关闭所有打开的文件描述符
- 44 intmax = open("/dev/null",0);
- 45 for(vari =0; i <= max; i++) { close(i); }
- 46
- 47
- 48 // 设置标记,防止重复运行进入
- 49Environment.SetEnvironmentVariable(DaemonTag,"yes");
- 50
- 51
- 52 //为execp参数重组参数
- 53 varargs1 = args ==nullnew string[2] :new string[args.Length +2];
- 54
- 55args1[0] ="MyDaemon";
- 56args1[1] = Path.Combine(Environment.CurrentDirectory, Thread.GetDomain().FriendlyName);
- 57
- 58 if(args1.Length >2)
- 59 {
- 60 for(vari =0; i < args.Length; i++)
- 61{ args1[i +2] = args[i]; }
- 62 }
- 63
- 64
- 65 //守护状态下重新加载和运行本程序
- 66execvp("mono", args1);
- 67
- 68 }
- 69
- 70
- 71 /// <summary>
- 72 /// Daemon工作状态的主方法
- 73 /// </summary>
- 74 /// <param name="aargs"></param>
- 75 static voidDaemonMain(string[] aargs)
- 76 {
- 77 //启动一个线程去处理一些事情
- 78(newThread(DaemonWorkFunct) { IsBackground =true }).Start();
- 79
- 80
- 81 //daemon时,控制台输入、输出流已经关闭
- 82 //请不要再用Console.Write/Read等方法
- 83
- 84 //阻止daemon进程退出
- 85(newAutoResetEvent(false)).WaitOne();
- 86
- 87 }
- 88
- 89
- 90 static FileStream fs;
- 91 static intcount =0;
- 92 static void DaemonWorkFunct() {
- 93fs = File.Open("/tmp/daemon.txt", FileMode.OpenOrCreate);
- 94 vart =newSystem.Timers.Timer() { Interval =1000 };
- 95t.Elapsed += OnElapsed;
- 96 t.Start();
- 97 }
- 98 private static voidOnElapsed(object sender, ElapsedEventArgs e)
- 99 {
- 100 vars = DateTime.Now.ToString("yyy-MM-dd HH:mm:ss") +"\n";
- 101 varb = Encoding.ASCII.GetBytes(s);
- 102fs.Write(b,0, b.Length);
- 103 fs.Flush();
- 104
- 105count++;
- 106 if(count >100) {
- 107 fs.Close();
- 108 fs.Dispose();
- 109exit(0);
- 110 }
- 111
- 112 }
- 113
- 114
- 115
- 116[DllImport("libc", SetLastError =true)]
- 117 static extern int fork();
- 118
- 119[DllImport("libc", SetLastError =true)]
- 120 static extern int setsid();
- 121
- 122[DllImport("libc", SetLastError =true)]
- 123 static extern intumask(int mask);
- 124
- 125[DllImport("libc", SetLastError =true)]
- 126 static extern intopen([MarshalAs(UnmanagedType.LPStr)]stringpathname,int flags);
- 127
- 128[DllImport("libc", SetLastError =true)]
- 129 static extern intclose(int fd);
- 130
- 131[DllImport("libc", SetLastError =true)]
- 132 static extern intexit(int code);
- 133
- 134[DllImport("libc", SetLastError =true)]
- 135 static extern intexecvp([MarshalAs(UnmanagedType.LPStr)]stringfile,string[] argv);
- 136
- 137
- 138 }
- 139
- 140}
以上代码的工作过程是:判断程序自身是否已经处于 daemon(后台服务) 状态,如果是,就直接开始具体的服务工作(开启一个线程,每秒向 /tmp/daemon.txt 中打印一行字符,100 次后退出),如果不是 daemon 状态,就进入 Daemon 处理,使之进入 daemon 工作状态。
以上代码编译后,会生成一个叫 daemon.exe 的程序,当然,这个程序是为 linux 开发的,不能在 windows 上运行。现在,我把它放到 linux 上面,用 mono daemon.exe 命令启动它。
这时我们可以看到这个程序启动后,控制台上没有任何输出,也没有阻塞控制台,那么,在哪儿能找到它呢?用 ps -ef 命令看看,原来它真的已经在后台运行起来了。
再看看这个后台进程是否完成了它的工作:cat /tmp/daemon.txt 查看文件内容:
从生成的文件内容看,这个 Daemon 服务程序的确按我们的设计意图,每秒钟向 / tmp/daemon.txt 打印了一行字符。
来源: http://www.cnblogs.com/yunei/p/6761218.html