幾年前,我寫過兩篇關於用C#開發Linux守護進程的技術文章,分別是《.NET跨平台實踐:用C#開發Linux守護進程》和《.NET跨平台實踐:再談用C#開發Linux守護進程 — 完整篇》。由於當時.net core還很稚嫩,沒有在業界得到廣泛使用,所以之前這兩篇文章的技術是針對Linux+Mono這個環境而言的。現在,.Net Core、.Net5已經大行其道,.Net6也很快就會發行正式版,因此,很有必要再加一篇,闡述一下怎么讓.net core以及.net5以上版本的.net程序也能在Linux環境下,以自身的能力成為貨真價實的Linux守護進程,而不是借用第三方工具!
這就是本文的初衷。
關於Linux Daemon程序的原理之類的,已經在之前的兩篇文章中得到了一些體現,因此,本文就直接上代碼,不在高大上的理論中去兜圈子了。
using System.Threading; using System.Timers; using System.Runtime.InteropServices; using System.IO; using System.Text; /************************************************ * .Net Core/.Net5+ Linux Daemon示例,作者宇內流雲 * ************************************************/ namespace daemon { class Program { static unsafe void Main(string[] args) { // 進入守護狀態 int pid = fork(); if (pid != 0) exit(0); setsid(); pid = fork(); if (pid != 0) exit(0); umask(0); // 關閉所有打開的文件描述符 int fd_nul = open("/dev/null", 0); for (var i = 0; i <= fd_nul; i++) { if (i < 3) dup2(fd_nul, i); else close(i); } // 進入主方法 //(本示例的功能很簡單,就是定時向某個文件寫入點內容) DaemonMain(args); } /// <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() { try { fs = File.Open(Path.Combine("/tmp", "daemon.txt"), FileMode.OpenOrCreate); } catch { exit(1); return; } 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 dup2(int oldfd, int newfd); } }
以上代碼就是Linux環境中,.NetCore或.Net5以上版本的.net程序,以純代碼方式使自身成為標准的Linux守護進程的示例代碼,你完全可以將它關鍵部分借用到自己的真實項目中。使用中如果有什么問題或建議,請加入本人的QQ群作進一步交流。
版權聲明:本文是 宇內流雲 (郵箱:j66x@163.com)原創作品,用c#開發原生的Linux守護進程相關技術及代碼亦屬本人首發。如需網絡轉載,請注明出處和作者;沒有得到本人書面授權,本人發布於網絡的任何關鍵代碼不得被任何團體或個人以任何名義使用到出版物中。