.NET跨平台實踐:再談用C#開發Linux守護進程 — 完整篇

來源:互聯網
上載者:User

標籤:dom   exe   功能   代碼   manage   port   rem   imp   private   

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 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] = "MyDaemon"; 56             args1[1] = Path.Combine(Environment.CurrentDirectory, Thread.GetDomain().FriendlyName); 57  58             if (args1.Length > 2) 59             { 60                 for (var i = 0; i < args.Length; i++) 61                 { args1[i + 2] = args[i]; } 62             } 63  64  65             //守護狀態下重新載入和運行本程式 66             execvp("mono", args1); 67  68         } 69  70  71         /// <summary> 72         /// Daemon工作狀態的主方法 73         /// </summary> 74         /// <param name="aargs"></param> 75         static void DaemonMain(string[] aargs) 76         { 77             //啟動一個線程去處理一些事情 78             (new Thread(DaemonWorkFunct) { IsBackground = true }).Start(); 79  80  81             //daemon時,控制台輸入、輸出資料流已經關閉 82             //請不要再用Console.Write/Read等方法 83  84             //阻止daemon進程退出 85             (new AutoResetEvent(false)).WaitOne(); 86  87         } 88  89  90         static FileStream fs; 91         static int count = 0; 92         static void DaemonWorkFunct() { 93             fs = File.Open("/tmp/daemon.txt", FileMode.OpenOrCreate); 94             var t = new System.Timers.Timer() { Interval = 1000 }; 95             t.Elapsed += OnElapsed; 96             t.Start(); 97         } 98         private static void OnElapsed(object sender, ElapsedEventArgs e) 99         {100             var s = DateTime.Now.ToString("yyy-MM-dd HH:mm:ss") + "\n";101             var b = Encoding.ASCII.GetBytes(s);102             fs.Write(b, 0, b.Length);103             fs.Flush();104 105             count++;106             if (count > 100) {107                 fs.Close();108                 fs.Dispose();109                 exit(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 int umask(int mask);124 125         [DllImport("libc", SetLastError = true)]126         static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, int flags);127 128         [DllImport("libc", SetLastError = true)]129         static extern int close(int fd);130 131         [DllImport("libc", SetLastError = true)]132         static extern int exit(int code);133 134         [DllImport("libc", SetLastError = true)]135         static extern int execvp([MarshalAs(UnmanagedType.LPStr)]string file, 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列印了一行字元。

.NET跨平台實踐:再談用C#開發Linux守護進程 — 完整篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.