利用C#编写Linux守护进程实例代码
前言
Linux守护进程是Linux的后台服务进程,相当于Windows服务,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是为了开发守护进程,还可以拓展到多进程,父子进程文件描述符共享,父子进程通讯、控制等方面,是实现Linux大型服务的基础技术之一。
如果要在Red Hat Enterprise Linux上将.NET Core进程作为后台进程运行,则可以创建自定义systemd单元。今天我将为.NET Core编写两个自定义系统单元的例子。一个是运行.NET Core控制台应用程序的一种类型,另一个是运行ASP.NET Core Web应用程序的简单类型。
控制台应用程序
建立一个应用程序
您可以用dotnet run在systemd中使用指定项目目录作为工作目录。但是,我们来构建一个二进制文件并将其用于systemd。用dotnet new 命令创建您的项目后编辑Program.cs如下。
using System; using System.IO; namespace ConsoleApplication { public class Program { public static void Main(string[] args) { var path = Path.GetTempFileName(); File.WriteAllText(path, "Hello Temp File!"); Console.WriteLine($"Wrote temp file: {path}"); } } }
然后用dotnet publish命令发布项目。你会看到bin/<Configuration>/<Framework>目录下的二进制文件。
$ dotnet publish -c Release Publishing ConsoleApp for .NETCoreApp,Version=v1.1 Project ConsoleApp (.NETCoreApp,Version=v1.1) was previously compiled. Skipping compilation. publish: Published to /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish Published 1/1 projects successfully
创建一个自定义的systemd
首先,创建一个运行守护进程和工作目录的用户。
$ sudo useradd -s /sbin/nologin dotnetuser $ sudo mkdir /var/SystemdExample $ sudo cp /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish/* /var/SystemdExample $ sudo chown -R dotnetuser:dotnetuser /var/SystemdExample
然后在/etc/systemd/system/目录下创建一个自定义的systemd单元文件。文件名应该是<unit-name>.<unit-type>。我创建的目录和文件名为:/etc/systemd/system/netcore-console-example.service。
[Unit] Description=Example for .NET Core ConsoleApp with systemd DefaultDependencies=no [Service] Type=oneshot RemainAfterExit=no ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll WorkingDirectory=/var/SystemdExample User=dotnetuser Group=dotnetuser [install]
您应该在ExecStart中指定dotnet的完整路径。以上是红帽提供的.NET Core 1.1的情况。然后你可以用systemctl命令执行守护进程。您可以使用systemctl status命令或journalctl命令查看控制台输出。
$ sudo systemctl start netcore-console-example.service $ sudo systemctl status netcore-console-example.service ● netcore-console-example.service - Example for .NET Core ConsoleApp with systemd Loaded: loaded (/etc/systemd/system/netcore-console-example.service; enabled; vendor preset: disabled) Active: inactive (dead) since Fri 2017-02-24 00:29:16 JST; 13s ago Process: 18075 ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll (code=exited, status=0/SUCCESS) Main PID: 18075 (code=exited, status=0/SUCCESS) Feb 24 00:29:16 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd... Feb 24 00:29:16 localhost.localdomain dotnet[18075]: Wrote temp file: /tmp/tmph1ok6H.tmp Feb 24 00:29:16 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd. $ journalctl -u netcore-console-example.service -e Feb 24 00:29:16 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd... Feb 24 00:29:16 localhost.localdomain dotnet[18075]: Wrote temp file: /tmp/tmph1ok6H.tmp Feb 24 00:29:16 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd. $ sudo cat /tmp/tmph1ok6H.tmp Hello Temp File!
使用PrivateTemp
在上述系统单元中,程序在临时文件夹下写入一个文件。你有时想写一个来自其他用户的临时文件是安全的。您可以在[Service]section中的指定使用PrivateTemp。
[Service] Type=oneshot RemainAfterExit=no ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll WorkingDirectory=/var/SystemdExample User=dotnetuser Group=dotnetuser PrivateTemp=true
重新加载单元文件后,程序可以像前一样访问/tmp目录,但这不是实际的/tmp目录。
$ sudo systemctl daemon-reload $ sudo systemctl start netcore-console-example.service $ sudo systemctl status netcore-console-example.service ● netcore-console-example.service - Example for .NET Core ConsoleApp with systemd Loaded: loaded (/etc/systemd/system/netcore-console-example.service; enabled; vendor preset: disabled) Active: inactive (dead) since Fri 2017-02-24 00:35:46 JST; 12s ago Process: 18415 ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet ConsoleApp.dll (code=exited, status=0/SUCCESS) Main PID: 18415 (code=exited, status=0/SUCCESS) Feb 24 00:35:46 localhost.localdomain systemd[1]: Starting Example for .NET Core ConsoleApp with systemd... Feb 24 00:35:46 localhost.localdomain dotnet[18415]: Wrote temp file: /tmp/tmpJLWAGC.tmp Feb 24 00:35:46 localhost.localdomain systemd[1]: Started Example for .NET Core ConsoleApp with systemd. $ ls /tmp/tmpJLWAGC.tmp ls: cannot access /tmp/tmpJLWAGC.tmp: No such file or directory
Web应用程序
建立一个应用程序
现在我们来构建一个ASP.NET Core Web应用程序。今天我使用默认的模板项目。
$ dotnet new -t web Created new C# project in /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp. $ dotnet restore ** snipped** log : Restore completed in 9721ms. $ dotnet publish -c Release Publishing WebApp for .NETCoreApp,Version=v1.1 ** snipped ** publish: Published to /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp/bin/Release/netcoreapp1.1/publish Published 1/1 projects successfully
现在可以用dotnet命令运行。
$ dotnet bin/Release/netcoreapp1.1/publish/WebApp.dll info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0] User profile is available. Using '/home/tatanaka/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. Hosting environment: Production Content root path: /home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp Now listening on: http://localhost:5000 Application started. Press Ctrl+C to shut down.
创建一个自定义的systemd
为这个Web应用程序也指定dotnetuser名称。
$ sudo mkdir /var/SystemdExample $ sudo cp -R bin/Release/netcoreapp1.1/publish/* /var/SystemdWebExample $ sudo chown -R dotnetuser:dotnetuser /var/SystemdWebExample
然后创建一个自定义的systemd单元文件/etc/systemd/system/netcore-web-example.service。
[Unit] Description=Example for .NET Core WebApp with systemd DefaultDependencies=no Wants=network.target # network is required After=network.target [Service] ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnet WebApp.dll WorkingDirectory=/var/SystemdWebExample Restart=always RestartSec=10 # Restart service after 10 seconds if dotnet service crashes SyslogIdentifier=dotnet-example User=dotnetuser Group=dotnetuser PrivateTmp=true Environment=ASPNETCORE_ENVIRONMENT=Production # specify environment variable for environment Environment=ASPNETCORE_URLS=http://*:8080 # specify environement variable for listening port [Install] WantedBy = multi-user.target
最后,您可以将ASP.NET Core应用程序作为Linux守护程序运行。请注意,此应用程序侦听端口8080代替了ASP.NET Core 默认的 5000,因为我在ASPNETCORE_URLS单元文件中指定了环境变量 。
$ systemctl start netcore-web-example.service [tatanaka@localhost WebApp]$ systemc^C [tatanaka@localhost WebApp]$ sudo systemctl status netcore-web-example.service [sudo] password for tatanaka: ● netcore-web-example.service - Example for .NET Core WebApp with systemd Loaded: loaded (/etc/systemd/system/netcore-web-example.service; disabled; vendor preset: disabled) Active: active (running) since Sat 2017-02-25 01:02:12 JST; 11s ago Main PID: 7041 (dotnet) CGroup: /system.slice/netcore-web-example.service └─7041 /opt/rh/rh-dotnetcore11/root/usr/bin/dotnet WebApp.dll Feb 25 01:02:12 localhost.localdomain systemd[1]: Started Example for .NET Core WebApp with systemd. Feb 25 01:02:12 localhost.localdomain systemd[1]: Starting Example for .NET Core WebApp with systemd... Feb 25 01:02:12 localhost.localdomain dotnet-example[7041]: info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0] Feb 25 01:02:12 localhost.localdomain dotnet-example[7041]: User profile is available. Using '/home/dotnetuser/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Hosting environment: Production Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Content root path: /var/SystemdWebExample Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Now listening on: http://*:8080 Feb 25 01:02:13 localhost.localdomain dotnet-example[7041]: Application started. Press Ctrl+C to shut down. $ journalctl -u netcore-web-example -xf -- Logs begin at Mon 2017-02-20 11:58:31 JST. -- Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2] Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Sending file. Request path: '/images/banner4.svg'. Physical path: '/var/SystemdWebExample/wwwroot/images/banner4.svg' Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request finished in 0.1973ms 200 image/svg+xml Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request starting HTTP/1.1 GET http://localhost:8080/favicon.ico Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2] Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Sending file. Request path: '/favicon.ico'. Physical path: '/var/SystemdWebExample/wwwroot/favicon.ico' Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Feb 25 01:02:36 localhost.localdomain dotnet-example[7041]: Request finished in 0.5824ms 200 image/x-icon
然而这对于ASP.NET Core的生产使用来说是不够的。你可能需要设置一个反向代理服务器,比如Jexus,nginx,防火墙等等。
Writing a Linux daemon in C#
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对猪先飞的支持。
相关文章
- 我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
- 这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
- 这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
- 这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
- 这篇文章主要介绍了C#中list用法,结合实例形式分析了C#中list排序、运算、转换等常见操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25