利用C#编写Linux守护进程实例代码
前言
Linux守护进程是Linux的后台服务进程,相当于Windows服务,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是为了开发守护进程,还可以拓展到多进程,父子进程文件描述符共享,父子进程通讯、控制等方面,是实现Linux大型服务的基础技术之一。
如果要在RedHatEnterpriseLinux上将.NETCore进程作为后台进程运行,则可以创建自定义systemd单元。今天我将为.NETCore编写两个自定义系统单元的例子。一个是运行.NETCore控制台应用程序的一种类型,另一个是运行ASP.NETCoreWeb应用程序的简单类型。
控制台应用程序
建立一个应用程序
您可以用dotnetrun在systemd中使用指定项目目录作为工作目录。但是,我们来构建一个二进制文件并将其用于systemd。用dotnetnew命令创建您的项目后编辑Program.cs如下。
usingSystem; usingSystem.IO; namespaceConsoleApplication { publicclassProgram { publicstaticvoidMain(string[]args) { varpath=Path.GetTempFileName(); File.WriteAllText(path,"HelloTempFile!"); Console.WriteLine($"Wrotetempfile:{path}"); } } }
然后用dotnetpublish命令发布项目。你会看到bin/
$dotnetpublish-cRelease PublishingConsoleAppfor.NETCoreApp,Version=v1.1 ProjectConsoleApp(.NETCoreApp,Version=v1.1)waspreviouslycompiled.Skippingcompilation. publish:Publishedto/home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish Published1/1projectssuccessfully
创建一个自定义的systemd
首先,创建一个运行守护进程和工作目录的用户。
$sudouseradd-s/sbin/nologindotnetuser $sudomkdir/var/SystemdExample $sudocp/home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/ConsoleApp/bin/Release/netcoreapp1.1/publish/*/var/SystemdExample $sudochown-Rdotnetuser:dotnetuser/var/SystemdExample
然后在/etc/systemd/system/目录下创建一个自定义的systemd单元文件。文件名应该是
[Unit] Description=Examplefor.NETCoreConsoleAppwithsystemd DefaultDependencies=no [Service] Type=oneshot RemainAfterExit=no ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetConsoleApp.dll WorkingDirectory=/var/SystemdExample User=dotnetuser Group=dotnetuser [install]
您应该在ExecStart中指定dotnet的完整路径。以上是红帽提供的.NETCore1.1的情况。然后你可以用systemctl命令执行守护进程。您可以使用systemctlstatus命令或journalctl命令查看控制台输出。
$sudosystemctlstartnetcore-console-example.service $sudosystemctlstatusnetcore-console-example.service ●netcore-console-example.service-Examplefor.NETCoreConsoleAppwithsystemd Loaded:loaded(/etc/systemd/system/netcore-console-example.service;enabled;vendorpreset:disabled) Active:inactive(dead)sinceFri2017-02-2400:29:16JST;13sago Process:18075ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetConsoleApp.dll(code=exited,status=0/SUCCESS) MainPID:18075(code=exited,status=0/SUCCESS) Feb2400:29:16localhost.localdomainsystemd[1]:StartingExamplefor.NETCoreConsoleAppwithsystemd... Feb2400:29:16localhost.localdomaindotnet[18075]:Wrotetempfile:/tmp/tmph1ok6H.tmp Feb2400:29:16localhost.localdomainsystemd[1]:StartedExamplefor.NETCoreConsoleAppwithsystemd. $journalctl-unetcore-console-example.service-e Feb2400:29:16localhost.localdomainsystemd[1]:StartingExamplefor.NETCoreConsoleAppwithsystemd... Feb2400:29:16localhost.localdomaindotnet[18075]:Wrotetempfile:/tmp/tmph1ok6H.tmp Feb2400:29:16localhost.localdomainsystemd[1]:StartedExamplefor.NETCoreConsoleAppwithsystemd. $sudocat/tmp/tmph1ok6H.tmp HelloTempFile!
使用PrivateTemp
在上述系统单元中,程序在临时文件夹下写入一个文件。你有时想写一个来自其他用户的临时文件是安全的。您可以在[Service]section中的指定使用PrivateTemp。
[Service] Type=oneshot RemainAfterExit=no ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetConsoleApp.dll WorkingDirectory=/var/SystemdExample User=dotnetuser Group=dotnetuser PrivateTemp=true
重新加载单元文件后,程序可以像前一样访问/tmp目录,但这不是实际的/tmp目录。
$sudosystemctldaemon-reload $sudosystemctlstartnetcore-console-example.service $sudosystemctlstatusnetcore-console-example.service ●netcore-console-example.service-Examplefor.NETCoreConsoleAppwithsystemd Loaded:loaded(/etc/systemd/system/netcore-console-example.service;enabled;vendorpreset:disabled) Active:inactive(dead)sinceFri2017-02-2400:35:46JST;12sago Process:18415ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetConsoleApp.dll(code=exited,status=0/SUCCESS) MainPID:18415(code=exited,status=0/SUCCESS) Feb2400:35:46localhost.localdomainsystemd[1]:StartingExamplefor.NETCoreConsoleAppwithsystemd... Feb2400:35:46localhost.localdomaindotnet[18415]:Wrotetempfile:/tmp/tmpJLWAGC.tmp Feb2400:35:46localhost.localdomainsystemd[1]:StartedExamplefor.NETCoreConsoleAppwithsystemd. $ls/tmp/tmpJLWAGC.tmp ls:cannotaccess/tmp/tmpJLWAGC.tmp:Nosuchfileordirectory
Web应用程序
建立一个应用程序
现在我们来构建一个ASP.NETCoreWeb应用程序。今天我使用默认的模板项目。
$dotnetnew-tweb CreatednewC#projectin/home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp. $dotnetrestore **snipped** log:Restorecompletedin9721ms. $dotnetpublish-cRelease PublishingWebAppfor.NETCoreApp,Version=v1.1 **snipped** publish:Publishedto/home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp/bin/Release/netcoreapp1.1/publish Published1/1projectssuccessfully
现在可以用dotnet命令运行。
$dotnetbin/Release/netcoreapp1.1/publish/WebApp.dll info:Microsoft.Extensions.DependencyInjection.DataProtectionServices[0] Userprofileisavailable.Using'/home/tatanaka/.aspnet/DataProtection-Keys'askeyrepository;keyswillnotbeencryptedatrest. Hostingenvironment:Production Contentrootpath:/home/tatanaka/Documents/git/tanaka-takayoshi/SystemdExample/1.1/WebApp Nowlisteningon:http://localhost:5000 Applicationstarted.PressCtrl+Ctoshutdown.
创建一个自定义的systemd
为这个Web应用程序也指定dotnetuser名称。
$sudomkdir/var/SystemdExample $sudocp-Rbin/Release/netcoreapp1.1/publish/*/var/SystemdWebExample $sudochown-Rdotnetuser:dotnetuser/var/SystemdWebExample
然后创建一个自定义的systemd单元文件/etc/systemd/system/netcore-web-example.service。
[Unit] Description=Examplefor.NETCoreWebAppwithsystemd DefaultDependencies=no Wants=network.target#networkisrequired After=network.target [Service] ExecStart=/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetWebApp.dll WorkingDirectory=/var/SystemdWebExample Restart=always RestartSec=10#Restartserviceafter10secondsifdotnetservicecrashes SyslogIdentifier=dotnet-example User=dotnetuser Group=dotnetuser PrivateTmp=true Environment=ASPNETCORE_ENVIRONMENT=Production#specifyenvironmentvariableforenvironment Environment=ASPNETCORE_URLS=http://*:8080#specifyenvironementvariableforlisteningport [Install] WantedBy=multi-user.target
最后,您可以将ASP.NETCore应用程序作为Linux守护程序运行。请注意,此应用程序侦听端口8080代替了ASP.NETCore默认的5000,因为我在ASPNETCORE_URLS单元文件中指定了环境变量 。
$systemctlstartnetcore-web-example.service [tatanaka@localhostWebApp]$systemc^C [tatanaka@localhostWebApp]$sudosystemctlstatusnetcore-web-example.service [sudo]passwordfortatanaka: ●netcore-web-example.service-Examplefor.NETCoreWebAppwithsystemd Loaded:loaded(/etc/systemd/system/netcore-web-example.service;disabled;vendorpreset:disabled) Active:active(running)sinceSat2017-02-2501:02:12JST;11sago MainPID:7041(dotnet) CGroup:/system.slice/netcore-web-example.service └─7041/opt/rh/rh-dotnetcore11/root/usr/bin/dotnetWebApp.dll Feb2501:02:12localhost.localdomainsystemd[1]:StartedExamplefor.NETCoreWebAppwithsystemd. Feb2501:02:12localhost.localdomainsystemd[1]:StartingExamplefor.NETCoreWebAppwithsystemd... Feb2501:02:12localhost.localdomaindotnet-example[7041]:info:Microsoft.Extensions.DependencyInjection.DataProtectionServices[0] Feb2501:02:12localhost.localdomaindotnet-example[7041]:Userprofileisavailable.Using'/home/dotnetuser/.aspnet/DataProtection-Keys'askeyrepository;keyswillnotbeencryptedatrest. Feb2501:02:13localhost.localdomaindotnet-example[7041]:Hostingenvironment:Production Feb2501:02:13localhost.localdomaindotnet-example[7041]:Contentrootpath:/var/SystemdWebExample Feb2501:02:13localhost.localdomaindotnet-example[7041]:Nowlisteningon:http://*:8080 Feb2501:02:13localhost.localdomaindotnet-example[7041]:Applicationstarted.PressCtrl+Ctoshutdown. $journalctl-unetcore-web-example-xf --LogsbeginatMon2017-02-2011:58:31JST.-- Feb2501:02:36localhost.localdomaindotnet-example[7041]:info:Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2] Feb2501:02:36localhost.localdomaindotnet-example[7041]:Sendingfile.Requestpath:'/images/banner4.svg'.Physicalpath:'/var/SystemdWebExample/wwwroot/images/banner4.svg' Feb2501:02:36localhost.localdomaindotnet-example[7041]:info:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Feb2501:02:36localhost.localdomaindotnet-example[7041]:Requestfinishedin0.1973ms200image/svg+xml Feb2501:02:36localhost.localdomaindotnet-example[7041]:info:Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Feb2501:02:36localhost.localdomaindotnet-example[7041]:RequeststartingHTTP/1.1GEThttp://localhost:8080/favicon.ico Feb2501:02:36localhost.localdomaindotnet-example[7041]:info:Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2] Feb2501:02:36localhost.localdomaindotnet-example[7041]:Sendingfile.Requestpath:'/favicon.ico'.Physicalpath:'/var/SystemdWebExample/wwwroot/favicon.ico' Feb2501:02:36localhost.localdomaindotnet-example[7041]:info:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Feb2501:02:36localhost.localdomaindotnet-example[7041]:Requestfinishedin0.5824ms200image/x-icon
然而这对于ASP.NETCore的生产使用来说是不够的。你可能需要设置一个反向代理服务器,比如Jexus,nginx,防火墙等等。
WritingaLinuxdaemoninC#
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。