خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

نحوه ایجاد دیمون در لینوکس

دیمون ها فرآیندهایی هستند که به صورت بی صدا در پس زمینه دستگاه شما اجرا می شوند. در اینجا نحوه کدنویسی شیاطین خود در لینوکس آورده شده است.

دیمون ها فرآیندهایی هستند که مستقیماً تحت کنترل کاربر اجرا نمی شوند بلکه در پس زمینه ارائه می شوند. معمولاً هنگام راه اندازی سیستم شروع به کار می کنند و تا زمانی که سیستم خاموش شود به طور مداوم اجرا می شوند. تنها تفاوت این فرآیندها با فرآیندهای معمولی این است که به هیچ وجه به کنسول یا صفحه نمایش پیام ارسال نمی کنند.

در اینجا نحوه ایجاد دیمون در ماشین لینوکس آمده است.

مقدمه ای کوتاه بر نحوه ایجاد شیاطین

بسیاری از دیمون ها بر روی سیستم اجرا می شوند و برخی از نمونه های آشنا به شرح زیر هستند:

  • crond: دستورات را در زمان مشخص اجرا می کند
  • sshd: اجازه ورود به سیستم را از ماشین های راه دور می دهد
  • httpd: صفحات وب را ارائه می دهد
  • nfsd: به اشتراک گذاری فایل از طریق شبکه اجازه می دهد

همچنین، فرآیندهای دیمون معمولاً با حرف d پایان می‌یابند، اگرچه اجباری نیست.

برای اینکه یک فرآیند به صورت دیمون اجرا شود، مسیر زیر دنبال می شود:

  • عملیات اولیه، مانند خواندن فایل های پیکربندی یا به دست آوردن منابع سیستم لازم، باید قبل از تبدیل شدن فرآیند به یک شبح انجام شود. به این ترتیب سیستم می تواند خطاهای دریافتی را به کاربر گزارش کند و با کد خطای مناسب فرآیند خاتمه می یابد.
  • یک فرآیند در حال اجرا پس‌زمینه با init به عنوان فرآیند والد ایجاد می‌شود. برای این منظور ابتدا یک فرآیند فرعی از فرآیند init جدا می شود و سپس فرآیند بالایی با خروج خاتمه می یابد.
  • یک جلسه جدید باید با فراخوانی تابع setsid باز شود و فرآیند باید از ترمینال جدا شود.
  • تمام توصیفگرهای فایل باز که از فرآیند والد به ارث رسیده اند بسته می شوند.
  • پیام های ورودی، خروجی و خطای استاندارد به /dev/null هدایت می شوند.
  • دایرکتوری کاری فرآیند باید تغییر کند.

Daemon Sessions چیست؟

پس از ورود به سیستم از طریق ترمینال، کاربران می توانند بسیاری از برنامه ها را از طریق برنامه پوسته اجرا کنند. هنگامی که کاربر از سیستم خارج می شود، این فرآیندها باید بسته شوند. سیستم عامل این فرآیندها را به دو گروه جلسه و فرآیند گروه بندی می کند.

هر جلسه شامل گروه های فرآیندی است. می توانید این وضعیت را به صورت زیر توصیف کنید:

دیمون-جلسات-نمودار

پایانه ای که در آن فرآیندها ورودی های خود را دریافت و خروجی های خود را ارسال می کنند، ترمینال کنترل نامیده می شود. یک ترمینال کنترلی تنها با یک جلسه در یک زمان مرتبط است.

مطلب مرتبط:   نحوه نصب WireGuard VPN Client

یک جلسه و گروه های فرآیند در آن دارای شماره شناسایی (ID) هستند. این شماره‌های شناسایی، شماره‌های شناسایی فرآیند (PID) رهبران جلسه و فرآیند هستند. یک فرآیند فرزند از همان گروهی که فرآیند والد خود دارد به اشتراک می گذارد. هنگامی که چندین فرآیند با مکانیزم لوله در ارتباط هستند، اولین فرآیند به رهبر گروه فرآیند تبدیل می شود.

ایجاد یک پردازش دیمون در لینوکس

در اینجا خواهید دید که چگونه می توانید یک تابع شبح ایجاد کنید. برای این منظور تابعی به نام _daemon ایجاد خواهید کرد. می‌توانید با نام‌گذاری کد برنامه‌ای که به‌عنوان دیمون اجرا می‌شود به‌عنوان test.c و کدی که تابع daemon را به‌عنوان daemon.c ایجاد می‌کنید، شروع کنید.

//test.c
#include <stdio.h>

int _daemon(int, int);

int main()
{
getchar();
_daemon(0, 0);
getchar();
return 0;
}

//daemon.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>
#include <linux/limits.h>
int _daemon(int nochdir, int noclose) {
 pid_t pid;
 pid = fork(); // Fork off the parent process
 if (pid < 0) {
   exit(EXIT_FAILURE);
 }
 if (pid > 0) {
   exit(EXIT_SUCCESS);
 }
 return 0;
}

برای ایجاد دیمون، به یک فرآیند پس زمینه نیاز دارید که فرآیند والد آن init باشد. در کد بالا، _daemon یک پردازش فرزند ایجاد می کند و سپس فرآیند والد را می کشد. در این صورت، فرآیند جدید شما یک زیرفرآیند از init خواهد بود و در پس‌زمینه به کار خود ادامه می‌دهد.

حالا اپلیکیشن را با دستور زیر کامپایل کنید و وضعیت فرآیند قبل و بعد از _deamon نامیده می شود را بررسی کنید:

gcc -o test test.c daemon.c

برنامه را اجرا کنید و بدون فشار دادن هیچ کلید دیگری به ترمینال دیگری بروید:

./test

می بینید که مقادیر مربوط به فرآیند شما به شرح زیر است. در اینجا، شما باید از دستور ps برای دریافت اطلاعات مربوط به فرآیند استفاده کنید. در این حالت، تابع _daemon هنوز فراخوانی نشده است.

ps -C test -o "pid ppid pgid sid tty stat command"

# Output
PID PPID PGID SID TT STAT COMMAND
10296 5119 10296 5117 pts/2 S+ ./test

وقتی به فیلد STAT نگاه می‌کنید، می‌بینید که فرآیند شما در حال اجرا است اما منتظر یک رویداد خارج از برنامه است که باعث می‌شود در پیش‌زمینه اجرا شود.

مطلب مرتبط:   کار با تاریخ و زمان در Rust

مخفف

معنی

اس

در خواب منتظر وقوع یک رویداد

تی

برنامه متوقف شد

س

رهبر جلسه

+

برنامه در پیش زمینه در حال اجرا است

می توانید ببینید که فرآیند اصلی برنامه شما همان طور که انتظار می رود پوسته است.

ps -jp 5119
# Output
PID PGID SID TTY TIME CMD
5119 5119 5117 pts/2 00:00:02 zsh

اکنون به ترمینالی که در آن برنامه خود را اجرا می کنید بازگردید و Enter را فشار دهید تا تابع _daemon فراخوانی شود. سپس دوباره به اطلاعات فرآیند در ترمینال دیگر نگاه کنید.

ps -C test -o "pid ppid pgid sid tty stat command"

# Output
PID PPID PGID SID TT STAT COMMAND
22504 1 22481 5117 pts/2 S ./test

اول از همه، می‌توانید بگویید که زیرفرایند جدید در پس‌زمینه اجرا می‌شود، زیرا شما کاراکتر + را در فیلد STAT نمی‌بینید. اکنون با استفاده از دستور زیر بررسی کنید که فرآیند والد فرآیند کیست:

ps -jp 1

​​​​​​​# Output
PID PGID SID TTY TIME CMD
1 1 1 ? 00:00:01 systemd

اکنون می توانید ببینید که فرآیند والد فرآیند شما، فرآیند systemd است. در بالا ذکر شد که برای مرحله بعدی باید یک جلسه جدید باز شود و فرآیند از ترمینال کنترل جدا شود. برای این کار از تابع setsid استفاده می کنید. این فراخوانی را به تابع _daemon خود اضافه کنید.

قطعه کدی که باید اضافه کنید به شرح زیر است:

if (setsid() == -1)
return -1;

اکنون که وضعیت قبل از فراخوانی _daemon را بررسی کرده اید، اکنون می توانید اولین تابع getchar را در کد test.c حذف کنید.

//test.c
#include <stdio.h>
int _daemon(int, int);
int main()
{
_daemon(0, 0);
getchar();
return 0;
}

پس از کامپایل و اجرای مجدد برنامه، به ترمینالی که در آن نظرات خود را انجام داده اید بروید. وضعیت جدید فرآیند شما به شرح زیر است:

ps -C test -o "pid ppid pgid sid tty stat command"

​​​​​​​# Output
PID PPID PGID SID TT STAT COMMAND
25494 1 25494 25494 ? Ss ./test

? علامت در فیلد TT نشان می دهد که فرآیند شما دیگر به ترمینال متصل نیست. توجه داشته باشید که مقادیر PID، PGID و SID فرآیند شما یکسان است. روند شما اکنون یک رهبر جلسه است.

در مرحله بعد، دایرکتوری کاری را با توجه به مقدار آرگومانی که پاس کردید، به دایرکتوری root تغییر دهید. برای این کار می توانید قطعه زیر را به تابع _daemon اضافه کنید:

if (!nochdir) {
   if (chdir("/") == -1)
      return -1;
}

اکنون، با توجه به آرگومان تصویب شده، تمام توصیفگرهای فایل می توانند بسته شوند. کد زیر را به تابع _daemon اضافه کنید:

#define NR_OPEN 1024
if (!noclose) {
   for (i = 0; i < NR_OPEN; i++)
      close(i);
   open("/dev/null", O_RDWR);
   dup(0);
   dup(0);
}

پس از بسته شدن همه توصیفگرهای فایل، فایل های جدیدی که توسط دیمون باز می شوند به ترتیب با توصیفگرهای 0، 1 و 2 نشان داده می شوند. در این حالت، برای مثال، دستورات printf در کد به دومین فایل باز شده هدایت می شوند. برای جلوگیری از این امر، سه شناسه اول به دستگاه /dev/null اشاره می کنند.

مطلب مرتبط:   لینوکس با بوت دوگانه زمان ویندوز را به هم ریخته است؟ در اینجا نحوه رفع آن آمده است

در این حالت، وضعیت نهایی تابع _daemon به صورت زیر خواهد بود:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
int _daemon(void) {
 // PID: Process ID
 // SID: Session ID
 pid_t pid, sid;
 pid = fork(); // Fork off the parent process
 if (pid < 0) {
   exit(EXIT_FAILURE);
 }
 if (pid > 0) {
   exit(EXIT_SUCCESS);
 }
 // Create a SID for child
 sid = setsid();
 if (sid < 0) {
   // FAIL
   exit(EXIT_FAILURE);
 }
 if ((chdir("/")) < 0) {
   // FAIL
   exit(EXIT_FAILURE);
 }
 close(STDIN_FILENO);
 close(STDOUT_FILENO);
 close(STDERR_FILENO);
 while (1) {
   // Some Tasks
   sleep(30);
 }
 exit(EXIT_SUCCESS);
}

در اینجا نمونه ای از یک قطعه کد است که برنامه sshd را به عنوان یک شبح اجرا می کند:

...
if (!(debug_flag || inetd_flag || no_daemon_flag)) {
    int fd;
    if (daemon(0, 0) < 0)
        fatal("daemon() failed: %.200s", strerror(errno));
    /* Disconnect from the controlling tty. */
    fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
    if (fd >= 0) {
        (void) ioctl(fd, TIOCNOTTY, NULL);
        close(fd);
    }
}
...

دیمون ها برای برنامه نویسی سیستم لینوکس مهم هستند

دیمون ها برنامه هایی هستند که اقدامات مختلفی را به شیوه ای از پیش تعریف شده در پاسخ به رویدادهای خاص انجام می دهند. آنها بی صدا روی دستگاه لینوکس شما اجرا می شوند. آنها تحت کنترل مستقیم کاربر نیستند و هر سرویسی که در پس‌زمینه اجرا می‌شود دیمون خود را دارد.

برای یادگیری ساختار هسته سیستم عامل لینوکس و درک عملکرد معماری های مختلف سیستم، تسلط بر دیمون ها مهم است.