.NET跨平台实践:再谈用C#开发Linux守护进程 — 完整篇

Linux守护进程是Linux的后台服务进程,相当于Windows服务,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是为了开发守护进程,还可以拓展到多进程,父子进程文件描述符共享,父子进程通讯、控制等方面,是实现Linux大型服务的基础技术之一。

去年我也曾写了一篇关于守护进程的帖子,名字叫《.NET跨平台实践:用C#开发Linux守护进程》,这篇文章的的确确实现了一个Daemon,不过,它有一个弱点,不能运行多线程!

这篇帖子的目的就是进一步完善,让我们写出一个功能完整,可以用于生产环节的基本的守护进程。

先帖代码(假设项目名是daemon):

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] = "MyDaemon";

            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);



    }


}

以上代码的工作过程是:判断程序自身是否已经处于daemon(后台服务)状态,如果是,就直接开始具体的服务工作(开启一个线程,每秒向 /tmp/daemon.txt中打印一行字符,100次后退出),如果不是daemon状态,就进入Daemon处理,使之进入daemon工作状态。

以上代码编译后,会生成一个叫 daemon.exe 的程序,当然,这个程序是为linux开发的,不能在windows上运行。现在,我把它放到linux上面,用mono daemon.exe命令启动它。

这时我们可以看到这个程序启动后,控制台上没有任何输出,也没有阻塞控制台,那么,在哪儿能找到它呢?用 ps -ef命令看看,原来它真的已经在后台运行起来了。

再看看这个后台进程是否完成了它的工作:cat /tmp/daemon.txt 查看文件内容:

从生成的文件内容看,这个Daemon服务程序的确按我们的设计意图,每秒钟向/tmp/daemon.txt打印了一行字符。

原文地址:http://www.cnblogs.com/yunei/p/6761218.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React中解决样式丢失问题

解决多级路径刷新页面样式丢失的问题 1.public/index.html 中 引入样式时不写 ./ 写 / &#xff08;常用&#xff09;2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% &#xff08;常用&#xff09;3.使用HashRouter

使用jQuery操作DOM元素

一、DOM分类&#xff1a; 1.DOM core 2.Html-DOM 3.CSS-DOM 二、css样式 $(this).css(“font-size”,“25px”); $(this).css({“font-size”:“30px”,“color”:“white”}); $("#div3").addClass(“div3_style”); //移除样式 $("#div3").removeClass(…

静态代理

1、接口 package AOP.proxy;/*** Created by Administrator on 2019/6/11.*/ public interface PersonDao {public void savePerson(); }2、目标实现类 package AOP.proxy;/*** Created by Administrator on 2019/6/11.*/ public class PersonDaoImpl implements PersonDao {…

选择大公司还是小公司

转载自 选择大公司还是小公司 本文转载自公众号 stormzhang&#xff0c;文中的“我”是原文作者。 前一段时间&#xff0c;我一知识星球的球友问我这么一个问题&#xff0c;说他是某 985 应届生&#xff0c;拿到了 BAT 一家互联网大公司的 offer&#xff0c;但同时他还拿到了…

未来的C#之只读引用与结构体

C中提供了const特性&#xff0c;使用该特性定义的参数&#xff0c;其所引用的参数或对象将不会被调用函数修改&#xff08;当然const还提供了更多的特性&#xff0c;参见“Const正确性”&#xff09;。在新的建议中&#xff0c;C#也将提供类似的特性。 只读ref参数 在C#中&am…

C++实现字符串的拼接

#include #include using namespace std; int main(){ //字符创的拼接 string a “rtmp://192.168.0.128:1935/live/Test”; string b “.flv”; a.append(b); cout<<a<<endl; string str; str.assign(a); //直接赋值 str.assign(str, 4, str.npos); //赋值给子…

表单验证

一、表单选择器&#xff1a; 用于选取某些特定的表单元素 二、常用的表单选择器&#xff1a; 1.:input,选取所有的textarea,button,input,select元素 eg:(&quot;:input&quot;).css(&quot;border&quot;,&quot;1pxsolidred&quot;);2.text选取所有的单行文…

React中BrowserRouter与HashRouter的区别

BrowserRouter与HashRouter的区别 1.底层原理不一样&#xff1a;BrowserRouter使用的是H5的history API&#xff0c;不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。2.path表现形式不一样BrowserRouter的路径中没有#,例如&#xff1a;localhost:3000/demo/testHashRoute…

漫画:什么是优先队列

转载自 漫画&#xff1a;什么是优先队列 在之前的漫画中&#xff0c;我们介绍了二叉堆和堆排序。没看过的小伙伴可以看一看前文&#xff1a; 漫画&#xff1a;什么是二叉堆&#xff1f;&#xff08;修正版&#xff09; 漫画&#xff1a;什么是堆排序&#xff1f; 这一次&a…

安全——《微服务设计》读书笔记

身份认证和授权 1.单点登录&#xff08;SSO&#xff09; 当主体试图访问一个资源&#xff0c;他会被定向到一个身份提供者那里进行身份验证&#xff0c;身份提供者验明正向后会发消息给服务提供者&#xff0c;让服务提供者来决定是否允许它访问资源。 SAML和OpenID Connect/OAu…

抽象和封装

一、软件出现的目的是为了&#xff1a; 1.用计算机语言描述现实世界。 2.用计算机解决现实世界中的问题。 二、面向对象&#xff1a; 1.与人类的思维习惯一致 2.代码可重用性高&#xff0c;可靠性高。 三、从现实世界中抽象出类&#xff1a; 1.发现类 2.发现类的属性 3.发现类的…

支付对账系统怎么设计

转载自 支付对账系统怎么设计 支付对账系统是整个支付清结算体系中具体基础性意义的一个环节&#xff0c;是确保支付平台与各类第三方支付渠道数据一致性的关键系统&#xff0c;是商户资金结算、资金划拨、资金报表等逻辑准确运行的重要前提。 支付对账涉及账单下载处理、核心…

十二个 ASP.NET Core 例子

前言 在今天的博客中&#xff0c;我将介绍十几个可以在 ASP.NET Core 应用程序中使用的简单示例。从最简单的东西开始&#xff0c;比如 Options, 中间件&#xff0c;数据库&#xff0c;甚至 Nginx 或者 Docker。 首先确定你已经执行过了 dotnet restore , 然后运行 dotnet ru…

Opencv FFmpeg Ubuntu下编译问题

FFmpeg转码错误Cannot load libcuda.so.1 https://blog.csdn.net/yzhang6_10/article/details/81349532 srs2.0 安装启动 https://my.oschina.net/fengjihu/blog/413710 SRS-HLS服务的部署 https://blog.csdn.net/dengjoe/article/details/52698423 ubuntu编译ffmpeg并且demo测…

40 道基础Dubbo 面试题及答案

转载自 40 道 Dubbo 面试题及答案 想往高处走&#xff0c;怎么能不懂 Dubbo&#xff1f; Dubbo是国内最出名的分布式服务框架&#xff0c;也是 Java 程序员必备的必会的框架之一。Dubbo 更是中高级面试过程中经常会问的技术&#xff0c;无论你是否用过&#xff0c;你都必须…

康威定律和系统设计——《微服务设计》读书笔记

康威定律 任何组织在设计一套系统时&#xff0c;所交付的设计方案在结构上都与该组织的沟通结构保持一致。 ——梅尔.康威 如何理解这句话在软件工程上的含义&#xff1f;埃里克.S.雷蒙德说&#xff1a;如果你有四个小组开发一个编译器&#xff0c;那你会得到一个四步编译器。…

Ubuntu下C++代码调用可执行文件。

例如&#xff1a;已经存在一个编译好的c可执行文件&#xff1a; 简单代码&#xff08;第一个可执行文件&#xff09; vim hello.cpp #include <iostream> using namespace std; int main(){cout<<"Ubuntu调用C可执行文件成功"<<endl;return 0; }编…