Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作。
一句话,为Linux开发与控制台无关的,需要在后台长时间不间断运行的“服务程序”,Daemon技术是非常重要的。
Daemon程序一般用c/c++开发。不过,我今天要讲的,不是怎么用c/c++开发daemon,而是用C#!
一,创建Daemon程序:
用VS新建一个控制台项目,假设名称是MyDaemon,输入下边的代码:
- 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] = "mono";
- 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);
- }
- }
二,部署和运行:
.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,就能终止它的运行。
============ 欢迎各位老板打赏~ ===========
与本文相关的文章
- · linux shell守护进程(daemon)
- · Linux下进程管理工具推荐:supervisor
- · Linux下配置 nginx + .net core 2.0
- · centos安装node18
- · The instance of entity type ‘Customer’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked.
- · .NET8实时更新nginx ip地址归属地
- · 解决.NET Blazor子组件不刷新问题
- · nginx日志按天分割
- · .NET8如何在普通类库中引用 Microsoft.AspNetCore
- · 解决Linux实例磁盘空间满问题
- · .NET8 Mysql SSL error
- · ASP.NET Core MVC的Razor视图渲染中文乱码的问题