网站首页 > 技术文章 正文
起因
本文主要是通过P/Invoke的方式调用系统API,让c#程序成为守护进程.
使用pstree查看进程间的关系
C#调用系统API实现守护进程
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace linuxapp
{
class MyDaemon
{
[DllImport("libc", SetLastError = true)]
private static extern int close(int fd);
[DllImport("libc", SetLastError = true)]
private static extern int fork();
[DllImport("libc", SetLastError = true)]
private static extern int exit(int status);
[DllImport("libc", SetLastError = true)]
private static extern int setsid();
[DllImport("libc", SetLastError = true)]
private static extern int chdir(string path);
[DllImport("libc", SetLastError = true)]
private static extern int umask(int cmask);
[DllImport("libc", SetLastError = true)]
private static extern int syslog(int priority, string message);
//将syslog.h文件中, log宏定义改为常量
const int LOG_EMERG = 0; /* system is unusable */
const int LOG_ALERT = 1; /* action must be taken immediately */
const int LOG_CRIT = 2; /* critical conditions */
const int LOG_ERR = 3; /* error conditions */
const int LOG_WARNING = 4; /* warning conditions */
const int LOG_NOTICE = 5; /* normal but significant condition */
const int LOG_INFO = 6; /* informational */
const int LOG_DEBUG = 7; /* debug-level messages */
/// <summary>
/// 设置为守护进程程序
/// </summary>
/// <returns></returns>
static int SetDaemon()
{
int pid = fork(); //fork创建当前进程的副本
if (pid < 0)
{
return -1;
}
if (pid > 0)
{
exit(0); //让父进程退出,让子进程成为孤儿进程,由系统进程领养,可以通过pstree查看
}
else
{
setsid(); //设置一个新的会话
chdir("/"); //设置当前程序的工作目录为根目录
umask(0); //设置umask为0
close(0); //关闭标准输入文件STDIN_FILENO
close(1); //关闭标准输出文件STDOUT_FILENO
close(2); //关闭标准错误输出文件STDERR_FILENO
}
return 0;
}
/// <summary>
/// 真正要执行的实现代码
/// 由于在SetDaemon函数中,将标准的输入输出文件及错误文件都关闭了,所以在Run函数中,是不能直接使用Console.WriteLine,可以使用:
/// 1.将日志信息通过syslog输出到系统日志中
/// 2.将日志信息写入到当前程序的日志(可使用nlog等日志组件)
/// </summary>
static void Run()
{
//这里只是模拟
while (true)
{
Thread.Sleep(30 * 1000); //休眠30秒,执行一次
syslog(LOG_INFO, "MyDaemon(csharp) is running"); //记录日志,查看cat /var/log/messages
}
}
static void Main(string[] args)
{
int result = SetDaemon();
if (result == -1)
{
return;
}
Run();
}
}
}
编译和运行(使用Mono)
#mcs 是mono的编译器
mcs MyDaemon.cs
#通过mono运行c#程序
mono MyDaemon.exe
查看进程关系和日志
#pstree 查看进程树
pstree
#查看系统日志(应该是Centos,后面换为Ubuntu Server)
cat /var/log/messages
#如何关闭守护进程
#1.先查找mono的进程id
ps -u root(当前用户) | grep mono
#2,根据进程id,关闭进程
kill -9 18197
支持dotnet core及dotnet 5/6(2021-08-10)
在2017年,.Net Core还不够火,即使在2021年,还是有一部分项目还没有迁移到.Net Core上,更别说迁移到.Net 5,其实上边守护进程的代码,不做任何改变就可以在.Net 5/6上运行.
尤其到.Net 5/6上,使用更方便,因为可以发布单文件.不用安装.Net 运行时/也不用安装Mono.还有一种就是NativeAOT这个暂不支持交叉编译.如果需要NativeAOT的可以参考这篇:
//在.Net 6 生成Native库,让C/C++调用
//https://www.qiufengblog.com/articles/dotnet-6-natvie-invoke.html
生成单文件及裁剪之后的文件大小:
生成单文件及裁剪的工程文件配置:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<!--发布时,生成单文件-->
<PublishSingleFile>true</PublishSingleFile>
<!--发布时,进行裁剪不需要的dll-->
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>
将文件上传到Linux服务器上:
#因为文件是在Windows生成的,在Linux上没法运行,要给文件可执行权限
chmod +x Daemon
#继续使用pstree查看Linux进程树
pstree
具体有没有运行成功,还是查看一下系统日志有没有写入成功.
由于Ubuntu 20.04系统日志文件名换为:syslog
#ubuntu 20.04查看系统日志
cat /var/log/syslog
猜你喜欢
- 2024-09-11 C# (Winform)实现USB HID自定义接口操作(控制下位机,如STM32)
- 2024-09-11 Tcp服务端一直sleep,客户端不断发送数据产生的问题
- 2024-09-11 C#中的进程与线程及其并发编程(c#多线程并发处理)
- 2024-09-11 在服务中默默地执行C#业务代码(在服务中默默地执行c#业务代码)
- 2024-09-11 C#中AutoResetEvent和ManualResetEvent使用场景
- 2024-09-11 C# AutoResetEvent 和 ManualResetEvent 在 WinForms 应用中的使用
- 2024-09-11 C#基础 DateTime详解(c# datetime.date)
- 2024-09-11 C# 面向对象 静态类和静态成员(c# 静态方法和实例方法)
- 2024-09-11 C#编程中如何使用线程(c#线程是什么)
- 2024-09-11 一篇文章搞懂C#中的接口(c#中接口怎么使用)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)