.NET跨平台实践:再谈用C#开发Linux守护进程 — 完整篇
Linux守護進程是Linux的后臺服務進程,相當于Windows服務,對于為Linux開發服務程序的朋友來說,Linux守護進程相關技術是必不可少的,因為這個技術不僅僅是為了開發守護進程,還可以拓展到多進程,父子進程文件描述符共享,父子進程通訊、控制等方面,是實現Linux大型服務的基礎技術之一。
去年我也曾寫了一篇關于守護進程的帖子,名字叫《.NET跨平臺實踐:用C#開發Linux守護進程》,這篇文章的的確確實現了一個Daemon,不過,它有一個弱點,不能運行多線程!
這篇帖子的目的就是進一步完善,讓我們寫出一個功能完整,可以用于生產環節的基本的守護進程。
先帖代碼(假設項目名是daemon):
using System;
using System.Threading;
using System.Timers;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
/********************************************
?* 一個完整的linux daemon示例,作者宇內流云 *
?********************************************/
namespace daemon
{
? ? class Program
? ? {
? ? ? ? const string DaemonTag = "--daemon.";
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? // 判斷是否已經進入Daemon狀態,如果是,就直接執行后臺主函數
? ? ? ? ? ? if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DaemonTag)) == false)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Environment.SetEnvironmentVariable(DaemonTag, null);
? ? ? ? ? ? ? ? DaemonMain(args);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? // 如果還沒有進入daemon狀態,就作daemon處理
? ? ? ? ? ? /
? ? ? ? ? ? int pid = fork();
? ? ? ? ? ? if (pid != 0) exit(0);
? ? ? ? ? ? setsid();
? ? ? ? ? ? pid = fork();
? ? ? ? ? ? if (pid != 0) exit(0);
? ? ? ? ? ? umask(0);
? ? ? ? ? ? // 這兒已經進入“守護進程”工作狀態了!
? ? ? ? ? ? // 關閉所有打開的文件描述符
? ? ? ? ? ? int max = open("/dev/null", 0);
? ? ? ? ? ? for (var i = 0; i <= max; i++) { close(i); }
? ? ? ? ? ? // 設置標記,防止重復運行進入
? ? ? ? ? ? Environment.SetEnvironmentVariable(DaemonTag,"yes");
? ? ? ? ? ? //為execp參數重組參數
? ? ? ? ? ? var args1 = args == null ? new string[2] : new string[args.Length + 2];
? ? ? ? ? ? args1[0] = "MyDaemon";
? ? ? ? ? ? args1[1] = Path.Combine(Environment.CurrentDirectory, Thread.GetDomain().FriendlyName);
? ? ? ? ? ? if (args1.Length > 2)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for (var i = 0; i < args.Length; i++)
? ? ? ? ? ? ? ? { args1[i + 2] = args[i]; }
? ? ? ? ? ? }
? ? ? ? ? ? //守護狀態下重新加載和運行本程序
? ? ? ? ? ? execvp("mono", args1);
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// Daemon工作狀態的主方法
? ? ? ? /// </summary>
? ? ? ? /// <param name="aargs"></param>
? ? ? ? static void DaemonMain(string[] aargs)
? ? ? ? {
? ? ? ? ? ? //啟動一個線程去處理一些事情
? ? ? ? ? ? (new Thread(DaemonWorkFunct) { IsBackground = true }).Start();
? ? ? ? ? ? //daemon時,控制臺輸入、輸出流已經關閉
? ? ? ? ? ? //請不要再用Console.Write/Read等方法
? ? ? ? ? ? //阻止daemon進程退出
? ? ? ? ? ? (new AutoResetEvent(false)).WaitOne();
? ? ? ? }
? ? ? ? static FileStream fs;
? ? ? ? static int count = 0;
? ? ? ? static void DaemonWorkFunct() {
? ? ? ? ? ? fs = File.Open("/tmp/daemon.txt", FileMode.OpenOrCreate);
? ? ? ? ? ? var t = new System.Timers.Timer() { Interval = 1000 };
? ? ? ? ? ? t.Elapsed += OnElapsed;
? ? ? ? ? ? t.Start();
? ? ? ? }
? ? ? ? private static void OnElapsed(object sender, ElapsedEventArgs e)
? ? ? ? {
? ? ? ? ? ? var s = DateTime.Now.ToString("yyy-MM-dd HH:mm:ss") + "\n";
? ? ? ? ? ? var b = Encoding.ASCII.GetBytes(s);
? ? ? ? ? ? fs.Write(b, 0, b.Length);
? ? ? ? ? ? fs.Flush();
? ? ? ? ? ? count++;
? ? ? ? ? ? if (count > 100) {
? ? ? ? ? ? ? ? fs.Close();
? ? ? ? ? ? ? ? fs.Dispose();
? ? ? ? ? ? ? ? exit(0);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int fork();
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int setsid();
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int umask(int mask);
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, int flags);
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int close(int fd);
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int exit(int code);
? ? ? ? [DllImport("libc", SetLastError = true)]
? ? ? ? static extern int execvp([MarshalAs(UnmanagedType.LPStr)]string file, string[] argv);
? ? }
}
以上代碼的工作過程是:判斷程序自身是否已經處于daemon(后臺服務)狀態,如果是,就直接開始具體的服務工作(開啟一個線程,每秒向 /tmp/daemon.txt中打印一行字符,100次后退出),如果不是daemon狀態,就進入Daemon處理,使之進入daemon工作狀態。
以上代碼編譯后,會生成一個叫 daemon.exe 的程序,當然,這個程序是為linux開發的,不能在windows上運行?,F在,我把它放到linux上面,用mono daemon.exe命令啟動它。
這時我們可以看到這個程序啟動后,控制臺上沒有任何輸出,也沒有阻塞控制臺,那么,在哪兒能找到它呢?用 ps -ef命令看看,原來它真的已經在后臺運行起來了。
再看看這個后臺進程是否完成了它的工作:cat /tmp/daemon.txt 查看文件內容:
從生成的文件內容看,這個Daemon服務程序的確按我們的設計意圖,每秒鐘向/tmp/daemon.txt打印了一行字符。
原文地址:http://www.cnblogs.com/yunei/p/6761218.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的.NET跨平台实践:再谈用C#开发Linux守护进程 — 完整篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 监控——《微服务设计》读书笔记
- 下一篇: mssql on linux 安装指导