分类

链接

2017 年 4 月
 12
3456789
10111213141516
17181920212223
24252627282930

近期文章

热门标签

新人福利,免费薅羊毛

现在位置:    首页 > .NET, LINUX > 正文
共享办公室出租
[转].NET跨平台实践:用C#开发Linux守护进程
.NET, LINUX 暂无评论 阅读(1,250)

Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作。

一句话,为Linux开发与控制台无关的,需要在后台长时间不间断运行的“服务程序”,Daemon技术是非常重要的。

Daemon程序一般用c/c++开发。不过,我今天要讲的,不是怎么用c/c++开发daemon,而是用C#!

一,创建Daemon程序:

用VS新建一个控制台项目,假设名称是MyDaemon,输入下边的代码:

  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 string DaemonTag = "--daemon.";
  19. static void Main(string[] args)
  20. {
  21. // 如果已经是daemon后台服务,就直接执行后台主函数
  22. if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DaemonTag)) == false)
  23. {
  24. Environment.SetEnvironmentVariable(DaemonTag, null);
  25. DaemonMain(args);
  26. return;
  27. }
  28.  
  29.  
  30. // 如果还不是daemon状态,就作daemon处理
  31. ///////////////////////////////////////////////
  32.  
  33. int pid = fork();
  34. if (pid != 0) exit(0);
  35. setsid();
  36. pid = fork();
  37. if (pid != 0) exit(0);
  38. umask(0);
  39.  
  40.  
  41. // 这儿已经进入“守护进程”工作状态了!
  42.  
  43. //关闭所有打开的文件描述符
  44. int max = open("/dev/null", 0);
  45. for (var i = 0; i <= max; i++) { close(i); }
  46.  
  47.  
  48. // 设置标记,防止重复运行
  49. Environment.SetEnvironmentVariable(DaemonTag,"yes");
  50.  
  51.  
  52. //为execp重组参数
  53. var args1 = args == null ? new string[2] : new string[args.Length + 2];
  54.  
  55. args1[0] = "mono";
  56. args1[1] = Path.Combine(Environment.CurrentDirectory, Thread.GetDomain().FriendlyName);
  57.  
  58. //复制参数
  59. if (args1.Length > 2)
  60. {
  61. for (var i = 0; i < args.Length; i++)
  62. { args1[+ 2] = args[i]; }
  63. }
  64.  
  65.  
  66. //守护状态下重新加载和运行本程序
  67. execvp("mono", args1);
  68.  
  69. }
  70.  
  71.  
  72. /// <summary>
  73. /// Daemon工作状态的主方法
  74. /// </summary>
  75. /// <param name="aargs"></param>
  76. static void DaemonMain(string[] aargs)
  77. {
  78. //启动一个线程去处理一些事情
  79. (new Thread(DaemonWorkFunct) { IsBackground = true }).Start();
  80.  
  81.  
  82. //daemon时,控制台输入、输出流已经关闭
  83. //请不要再用Console.Write/Read等方法
  84.  
  85. //阻止daemon进程退出
  86. (new AutoResetEvent(false)).WaitOne();
  87.  
  88. }
  89.  
  90.  
  91. static FileStream fs;
  92. static int count = 0;
  93. static void DaemonWorkFunct() {
  94. fs = File.Open("/tmp/daemon.txt", FileMode.OpenOrCreate);
  95. var t = new System.Timers.Timer() { Interval = 1000 };
  96. t.Elapsed += OnElapsed;
  97. t.Start();
  98. }
  99. private static void OnElapsed(object sender, ElapsedEventArgs e)
  100. {
  101. var s = DateTime.Now.ToString("yyy-MM-dd HH:mm:ss") + "\n";
  102. var b = Encoding.ASCII.GetBytes(s);
  103. fs.Write(b, 0, b.Length);
  104. fs.Flush();
  105.  
  106. count++;
  107. if (count > 100) {
  108. fs.Close();
  109. fs.Dispose();
  110. exit(0);
  111. }
  112.  
  113. }
  114.  
  115. [DllImport("libc", SetLastError = true)]
  116. static extern int fork();
  117.  
  118. [DllImport("libc", SetLastError = true)]
  119. static extern int setsid();
  120.  
  121. [DllImport("libc", SetLastError = true)]
  122. static extern int umask(int mask);
  123.  
  124. [DllImport("libc", SetLastError = true)]
  125. static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, int flags);
  126.  
  127. [DllImport("libc", SetLastError = true)]
  128. static extern int close(int fd);
  129.  
  130. [DllImport("libc", SetLastError = true)]
  131. static extern int exit(int code);
  132.  
  133. [DllImport("libc", SetLastError = true)]
  134. static extern int execvp([MarshalAs(UnmanagedType.LPStr)]string file, string[] argv);
  135.  
  136.  
  137. }
  138.  
  139. }
然后编译为 MyDaemon.exe。

二,部署和运行:

.net 程序在linux运行,一般都会使用mono这个.net框架,不过,为了简单方便,我这里使用 AnyExec来运行这个程序(关于AnyExec,请参阅:不装mono,你的.NET程序照样可以在Linux上运行!)。

1,把 MyDeamon.exe放到anyexec的app文件夹;

2,把 "any"这个程序复制为 MyDeamon;

3,运行:见证神奇的时间到了!请你在linux控制终端上输入: ./MyDaemon,哈哈,怎么没有反应? 其实,不是没有反应,是你这个 MyDaemon程序已经在后台跑起来了!

输入 “ps -ef”,看看!

看到那个 MyDaemon了吧!这次运行的PID是11618,父进程是的PID是1,1是谁?linux init!

4,退出daemon程序:daemon程序不会与控制台输入输出进行交互,所以,用Console.ReadLine之类的方法控制进程的退出是不现实的。那么,怎么关闭这个在后台运行的 daemon呢? 最简办法就是用ps -ef查出这个进程的PID号,然后用kill命令终止它。比如当前运行的这个 mydaemon的PID号是 11618,你只需要输入 kill -9 11618,就能终止它的运行。

============ 欢迎各位老板打赏~ ===========

本文版权归Bruce's Blog所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:[转].NET跨平台实践:用C#开发Linux守护进程 | Bruce's Blog

发表评论

留言无头像?