検索
ホームページシステムチュートリアルLinuxLinux のデーモン: 単純なデーモンの作成方法と使用方法
Linux のデーモン: 単純なデーモンの作成方法と使用方法Feb 14, 2024 pm 10:42 PM
linuxLinuxチュートリアルLinuxシステムLinuxコマンドシェルスクリプト埋め込みLinuxLinux を始めるLinux学習

デーモン プロセスは、Linux システムの特別なプロセスです。制御端末なしでバックグラウンドで実行され、ユーザーの介入を受けません。システムまたはアプリケーション関連のタスクと機能の実行を担当します。デーモンの役割は、予期せぬ事故や異常に対処するためにシステムの安定性と効率を向上させることです。組み込み Linux デバイスでは、デーモン プロセスを使用してシステムのメイン プロセスを保護し、システムが完全にクラッシュしてユーザー エクスペリエンスが損なわれる原因となる異常終了を防ぐことができます。しかし、Linux 上のデーモン プロセスを本当に理解していますか? Linux で簡単なデーモンを作成して使用する方法をご存知ですか?この記事では、Linux でのデーモン プロセスの関連知識を詳しく紹介し、Linux でこの強力なプロセス タイプをよりよく使用し、理解できるようにします。

Linux 下的守护进程:如何编写和使用简单的守护进程

Linux デバイスにデーモン プロセスを作成して、システムのメイン プロセスを保護し、予期せぬ事故によってメイン プロセスが異常終了し、応答なしにシステムが完全にシャットダウンしてユーザー エクスペリエンスが破壊されることを防ぎます。しかし、多くの情報を検討した結果、ほとんどの人は x86 プラットフォームでデーモン プロセスを作成して実装する方法についてのみ話しており、組み込みプラットフォームでデーモン プロセスを作成して実装する方法を紹介する人は誰もいなかったことがわかりました。そこで、いくつかの探索を行い、原理からコードに至るまでのすべてを一般的に理解した後、私自身でいくつかのアイデアを思いつきました。以下に簡単な概要と構成を示します。

1. 技術原則

以下は、x86 Linux システムのデーモン プロセスの紹介と説明に関するインターネットからの抜粋です。

Daemon はバックグラウンドで実行される特別なプロセスであり、制御端末から独立しており、定期的に特定のタスクを実行したり、特定のイベントの処理を待機したりします。

デーモン プロセスは特殊な孤立プロセスです。この種のプロセスは端末から分離されています。なぜ端末から分離する必要があるのでしょうか?端末から切り離しているのは、端末が生成する情報によって処理が中断されることを防ぐためであり、実行中の情報はどの端末にも表示されません。 Linux では、各システムがユーザーと通信するためのインターフェースをターミナルと呼ぶため、このターミナルから実行を開始するすべてのプロセスはこのターミナルに接続されます。このターミナルは、これらのプロセスの制御ターミナルと呼ばれます。 , 該当するプロセスが自動的に終了します。ただし、デーモン プロセスはこの制限を突破することができます。デーモン プロセスはターミナルから切り離され、バックグラウンドで実行されます。ターミナルから切り離される目的は、実行中のプロセス中の情報がターミナルに表示されないようにするためです。どの端末からもアクセスできません。生成された端末メッセージによって中断されます。実行されると実行を開始し、システム全体がシャットダウンされるまで終了しません (もちろん、対応するデーモン プロセスを強制終了すると考えることもできます)。プロセスがユーザー、中断、その他の変更の影響を受けないようにする場合は、このプロセスをデーモン プロセスに変える必要があります。

2. 設計手順

x86 プラットフォーム上の Linux システムの場合、理論的には、上記の効果を実現するために、デーモン プロセスには厳密な実装手順が必要です。つまり、デーモン プロセスは、他のタスクの干渉や影響を受けることなくバックグラウンドで安定して実行できるように、起動の開始時にシステム関連の制限をいくつか削除する必要があります。

x86 プラットフォームでデーモンを作成する基本的なプロセスは次のとおりです:

  1. 端末の動作を制御する一部の信号をブロックします。これは、制御端末が妨害されて、デーモンが実行される前に終了したりハングしたりするのを防ぐためです。信号の使用方法の詳細については、「信号割り込みの処理」を参照してください。
  2. バックグラウンドで実行されます。これは、制御端末のハングを避けるためにデーモン プロセスをバックグラウンドに置くためです。その方法は、プロセス内で fork() を呼び出して親プロセスを終了し、子プロセスのバックグラウンドでデーモンを実行させることです。
  3. 端末、ログインセッション、プロセスグループの制御を切り離します。まず、Linux におけるプロセスと制御端末、ログイン セッションとプロセス グループの関係を紹介する必要があります。プロセスはプロセス グループに属し、プロセス グループ番号 (GID) はプロセス グループ リーダーのプロセス番号 (PID) です。 。ログイン セッションには複数のプロセス グループを含めることができます。これらのプロセス グループは制御端末を共有します。この制御端末は通常、プロセスの作成元となったシェル ログイン端末です。制御端末、ログイン セッション、プロセス グループは通常、親プロセスから継承されます。私たちの目標は、それらを排除し、それらの影響を受けないようにすることです。したがって、子に新しいセッション リーダーを処理させるには、setsid() を呼び出す必要があります。 etsid() 呼び出しが成功すると、プロセスは新しいセッション グループ リーダーおよび新しいプロセス グループ リーダーになり、元のログイン セッションおよびプロセス グループから分離されます。セッションプロセスは制御端末への排他性があるため、同時にプロセスは制御端末から切り離されます。
  4. プロセスが制御端末を再度オープンしないようにします。現在、プロセスはターミナルレス セッション リーダーになっていますが、制御ターミナルを開くために再適用できます。子プロセスを再度作成することで、プロセスがセッション リーダーでなくなることで、制御ターミナルを再度開くことを防ぐことができます。
  5. 開いているファイル記述子を閉じます。プロセスは、そのプロセスを作成した親プロセスからオープン ファイル記述子を継承します。閉じていない場合、システム リソースが無駄になり、プロセスが存在するファイル システムをアンマウントできなくなり、予期しないエラーが発生します。
  6. 現在の作業ディレクトリを変更します。プロセスがアクティブな間は、その作業ディレクトリを含むファイル システムをマウント解除することはできません。通常、作業ディレクトリをルート ディレクトリに変更する必要があります。実行する必要があるコア ダンプの場合、実行ログを書き込むプロセスにより、作業ディレクトリが /tmp などの特定のディレクトリに変更されます。
  7. ファイル作成マスクをリセットします。プロセスは、それを作成した親プロセスからファイル作成マスクを継承します。デーモンによって作成されたファイルのアクセス許可が変更される可能性があります。これを防ぐには、ファイル作成マスクをクリアする必要があります。
  8. SIGCHLD シグナルを処理します。一部のプロセス、特にサーバー プロセスでは、リクエストが到着したときにリクエストを処理するために子プロセスが生成されることがよくあります。親プロセスが子プロセスの終了を待たない場合、子プロセスはゾンビ プロセス (ゾンビ) となり、システム リソースを占有します (ゾンビ プロセスの詳細については、「ゾンビ プロセス」を参照してください)。親プロセスが子プロセスの終了を待機すると、親プロセスの負担が増加し、サーバー プロセスの同時実行パフォーマンスに影響します。 Linux では、SIGCHLD 信号の動作を SIG_IGN に設定するだけで済みます。このようにして、カーネルは子プロセスが終了するまでゾンビ プロセスを生成しません。


以下は、先輩のブログから抜粋したソース コードの完全なセットです:

リーリー

3. 実際の状況

上記のプロセス ロジックと実際のコードから、x86 プラットフォームのデーモン プロセスは実際には非常に複雑で、多くの面倒な初期化プロセスが必要であることがわかります。しかし、組み込みプラットフォームの場合、そのような複雑な処理はなく、プロセスはより単純になるようです。なぜなら、この組み込みシステムではデーモンプロセスが有効になっているからです。このデーモンプロセスを利用して別のデーモン化プロセスを起動し、そのプロセスが正常に動作しているかを定期的に監視し、異常動作を発見した場合には直ちにプロセスを再起動することが目的です。

そこで、上記のプロセスを簡略化し、次のプロセスを得ました:

  1. デーモンプロセスで監視が必要なプロセスを起動します。
  2. デーモン プロセスにスレッドを作成して、デーモン プロセスの実行ステータスを定期的に監視します。
  3. デーモンプロセスは、デーモン化されたプロセスが正常に動作しているかどうかを判断し、異常な動作を検出すると、直ちにプロセスを再起動します。

4. 実際のソースコード

以下は、この組み込みシステム プロジェクトで設計されたデーモン プロセス モジュールの完全なコードです。

/******************************************************************************************

******** ** 函数名称: lockfile ** 功能描述: 对文件加锁/解锁 ** 输入参数: lock: 1表示进行加锁处理,

0表示进行解锁处理 ** 输出参数: 无 ** 返回参

数: 无 *************************************************************************************

*************/ int tryto_lockfile(int fd, int lock) { struct flock fl; fl.l_type = (lock =

= 1) ? F_WRLCK : F_UNLCK; fl.l_start = 0; fl.l_whence = SEEK_SET; fl.l_len = 0; return (f

cntl(fd, F_SETLK, &fl)); } /***************************************************************

*********************************** ** 函数名称: get_proc_running_state ** 功能描述: 获取进程

运行状态 ** 输入参数: 无 ** 输出参数: 无 ** 返回参数: 返回-1表示路径错误 ** 返回参数: 返回0表示进程

从未运行过,返回1表示进程曾经运行过但是现在停止运行了,返回2表示进程正在运行

中 ****************************************************************************************

**********/ static int get_proc_running_state(const char* filename) { int fd; if (filename

 == NULL) { /* 文件名为

空 */ return -1; } fd = open(filename, O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); i

f (fd 0) { /* 文件不存在,表示进程从未运行

过 */ return 0; } if (tryto_lockfile(fd, 1) == -1) { /* 文件加锁失败,表示进程在运行

中 */ close(fd); return 2; } else { /* 文件加锁成功,表示进程已经消

失 */ tryto_lockfile(fd, 0); /* 此处要注意记得解锁和关闭文

件 */ close(fd); return 1; } } /***********************************************************

*************************************** ** 函数名称: proc_watch ** 功能描述: 检测进程是否有在运

行,没有运行则重新启动之 ** 输入参数: procname: 进程名 ** 输出参数: 无 ** 返回参数: 返回-1表示进程从

未运行过;返回0表示进程当前运行正常; ** 返回参数: 返回其他非零值表示进程不存在且已被重新启动,返回的值

是新的pid值 ***************************************************************************

***********************/ int proc_watch(const char *procname) { int result, state; char fi

lename[100]; result = 0; sprintf(filename, "/var/run/%s.pid", procname); state = get_proc_

running_state(filename); switch (state) { case 0: result = -1; break; case 1: result = sta

rt_proc_by_name(procname); break; case 2: result = 0; break; default: break; } return resu

lt; } /************************************************************************************

************** ** 函数名称: start_proc ** 功能描述: 启动进程开始运行 ** 输入参数: 无 ** 输出参

数: 无 ** 返回参数: 进程的ID号,若启动失败则返回

0 *****************************************************************************************

*********/ int start_proc_by_name(const char* procname) { pid_t pid, child_pid; char filen

ame[100]; sprintf(filename, "%s%s", PROC_FILE_PATH, procname); child_pid = 0; if (access(f

ilename, X_OK | F_OK) != 0) { /* 如果文件存在,并且可执行 */ return 0; } pid = fork(); /* 首

先要fork一个进程出来 */ if (pid 0) { /* 创建进程失

败 */ return 0; } else if (pid == 0) { /* 创建进程成功,此处是子进程的代

码 */ if (execl(filename, procname, (char *)NULL) != -1) { return 1; } else { return 0; } 

} else { /* 创建进程成功,此处是父进程代


******************************************************************* ** 函数名

称: thread_client_hdl ** 功能描述: client进程监视线程 ** 输入参数: 无 ** 输出参数: 无 ** 返回参

数: 无 *************************************************************************************

*************/ static void *thread_client_hdl(void *pdata) { int result; pdata = pdata; sl

eep(10); /* 第一次要进行延

时 */ for (;;) { printf("time to check thread_client...\n"); result = proc_watch(PROC_NAME



_CLIENT); if (result == -1) { printf("thread_client never exist...\n"); } else if (result 

== 0) { printf("thread_client running ok...\n"); } else { printf("thread_client has gone! 

but restarted...\n"); } sleep(10); } return NULL; } /*************************************

************************************************************* ** 函数名称: main ** 功能描

述: 入口主函数 ** 输入参数: 无 ** 输出参数: 无 ** 返回参

数: 无 *************************************************************************************

*************/ int main(int argc, char *argv[]) { int client_para; char *p, *process_name;

 pthread_t thread_client; process_name = argv[0]; /* 获取进程名

称 */ p = process_name + strlen(process_name); while (*p != '/' && p != process_name) { p-

-; } if (*p == '/') { process_name = p + 1; } printf("\"%s\" starting...\n", process_name)

; client_para = 0x01; if (pthread_create(&thread_client, NULL, thread_client_hdl, &client_

para) != 0) { printf("create thread_client failed!\n"); return 1; } if (start_proc_by_name

(PROC_NAME_CLIENT) == 0) { printf("start thread_client failed!\n"); return 1; } for (;;) {

 sleep(60); printf("i am still alive...\n"); } return 0; }

通过本文,你应该对 Linux 下的守护进程有了一个基本的了解,知道了它的定义、特点和用途。你也应该明白了如何在 Linux 下编写和使用简单的守护进程,以及使用守护进程时需要注意的一些问题和技巧。我们建议你在使用 Linux 系统时,使用守护进程来提高系统的稳定性和效率。同时,我们也提醒你在使用守护进程时要注意一些潜在的问题和挑战,如信号处理、日志记录、资源管理等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下掌握守护进程的编写和使用。

以上がLinux のデーモン: 単純なデーモンの作成方法と使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は良许Linux教程网で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
什么是linux设备节点什么是linux设备节点Apr 18, 2022 pm 08:10 PM

linux设备节点是应用程序和设备驱动程序沟通的一个桥梁;设备节点被创建在“/dev”,是连接内核与用户层的枢纽,相当于硬盘的inode一样的东西,记录了硬件设备的位置和信息。设备节点使用户可以与内核进行硬件的沟通,读写设备以及其他的操作。

Linux中open和fopen的区别有哪些Linux中open和fopen的区别有哪些Apr 29, 2022 pm 06:57 PM

区别:1、open是UNIX系统调用函数,而fopen是ANSIC标准中的C语言库函数;2、open的移植性没fopen好;3、fopen只能操纵普通正规文件,而open可以操作普通文件、网络套接字等;4、open无缓冲,fopen有缓冲。

linux中什么叫端口映射linux中什么叫端口映射May 09, 2022 pm 01:49 PM

端口映射又称端口转发,是指将外部主机的IP地址的端口映射到Intranet中的一台计算机,当用户访问外网IP的这个端口时,服务器自动将请求映射到对应局域网内部的机器上;可以通过使用动态或固定的公共网络IP路由ADSL宽带路由器来实现。

linux怎么判断pcre是否安装linux怎么判断pcre是否安装May 09, 2022 pm 04:14 PM

在linux中,可以利用“rpm -qa pcre”命令判断pcre是否安装;rpm命令专门用于管理各项套件,使用该命令后,若结果中出现pcre的版本信息,则表示pcre已经安装,若没有出现版本信息,则表示没有安装pcre。

linux中eof是什么linux中eof是什么May 07, 2022 pm 04:26 PM

在linux中,eof是自定义终止符,是“END Of File”的缩写;因为是自定义的终止符,所以eof就不是固定的,可以随意的设置别名,linux中按“ctrl+d”就代表eof,eof一般会配合cat命令用于多行文本输出,指文件末尾。

linux怎么查询mac地址linux怎么查询mac地址Apr 24, 2022 pm 08:01 PM

linux查询mac地址的方法:1、打开系统,在桌面中点击鼠标右键,选择“打开终端”;2、在终端中,执行“ifconfig”命令,查看输出结果,在输出信息第四行中紧跟“ether”单词后的字符串就是mac地址。

手机远程linux工具有哪些手机远程linux工具有哪些Apr 29, 2022 pm 05:30 PM

手机远程linux工具有:1、JuiceSSH,是一款功能强大的安卓SSH客户端应用,可直接对linux服务进行管理;2、Termius,可以利用手机来连接Linux服务器;3、Termux,一个强大的远程终端工具;4、向日葵远程控制等等。

linux中lsb是什么意思linux中lsb是什么意思May 07, 2022 pm 05:08 PM

linux中,lsb是linux标准基础的意思,是“Linux Standards Base”的缩写,是linux标准化领域中的标准;lsb制定了应用程序与运行环境之间的二进制接口,保证了linux发行版与linux应用程序之间的良好结合。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール