• 《Unix 网络编程》13:守护进程和 inetd 超级服务器


    守护进程和 inetd 超级服务器

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    系列文章导航:《Unix 网络编程》笔记

    守护进程

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    基本知识

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    守护进程的特点:

    • 必须亲自脱离与控制终端的关联,从而避免与作业控制、终端会话管理、终端产生信号等发生任何不期望的交互
    • 同时要避免在后台运行的守护进程非预期地输出到终端

    守护进程的启动

    • 由系统初始化脚本启动,通常位于 /etc/rc/etc 目录下,由这些脚本启动的守护进程一开始就有用超级用户特权

      如:inetd 超级服务器、Web 服务器、sendmail 服务器

    • 由 inetd 超级服务器启动,它监听网络请求

    • cron 守护进程按照规则定期执行一些程序,由它执行的程序同样作为守护进程运行

    • at 命令用于在未来某个时刻执行一些程序

    • 守护进程还可以从用户终端或在前台或者后台启动,这么做往往是为了测试

    daemon_init

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    • 这是我们自己写的一个函数,把一个普通进程转变为守护进程
    • 部分 Unix 变体上提供一个名为 daemon 的 C 库函数,实现类似的功能

    由于这段代码涉及的知识点比较多,所以首先需要补充一点操作系统的知识:Linux 进程、进程组、会话周期、控制终端

    按照上文中的描述阅读下述代码:

    1. 在父进程(此时是一个进程组的组长)中使用fork()产生子进程(将来的守护进程由它产生)
    2. 调用setsid(),用于生成一个新的会话 注意如果当前进程是会话组长时,调用失败。第一点已经可以保证进程不是会话组长了,所以setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话对控制终端的独占性,进程同时与控制终端脱离
    3. 禁止进程重新打开控制终端 第二步之后,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端,在上面的控制终端中已经提到了只有会话组长才能打开控制终端;
    #include <syslog.h>
    #include "unp.h"
    
    #define MAXFD 64
    
    extern int daemon_proc; /* defined in error.c */
    
    int daemon_init(const char* pname, int facility) {
        int i;
        pid_t pid;
    
        if ((pid = Fork()) < 0) // 失败
            return (-1);
        else if (pid)   // 父进程
            _exit(0); /* parent terminates */
    
        /* child 1 continues... */
    
        // setsid 使得当前进程变为:
        // - 新会话的会话头进程
        // - 新进程组的进程组头进程
        if (setsid() < 0)
            return (-1);
    
        // 忽略 SIGHUP 信号
        // 会话头进程终止后,所有其他会话进程都会收到一个该信号
        Signal(SIGHUP, SIG_IGN);
        if ((pid = Fork()) < 0)
            return (-1);
        else if (pid)
            _exit(0); /* child 1 terminates */
    
        /* child 2 continues... */
    
        // 告知错误处理函数使用 syslog 而不是 fprintf
        daemon_proc = 1; /* for err_XXX() functions */
    
      	// 改变工作目录,否则就是在当前目录下运行,可能产生破坏
        chdir("/");
    
        // 关闭前 64 个描述符,即使有些本身就没有打开
        for (i = 0; i < MAXFD; i++)
            close(i);
    
        /* redirect stdin, stdout, and stderr to /dev/null */
        // 这样设置会占用标准输入、标准输出和标准错误输出的描述符
        // 防止在服务器环境下,套接字占用这些描述符,而后误将系统信息发送给这些描述符
        open("/dev/null", O_RDONLY);
        open("/dev/null", O_RDWR);
        open("/dev/null", O_RDWR);
    
        openlog(pname, LOG_PID, facility);
    
        return (0); /* success */
    }
    

    守护进程在没有控制终端的环境下运行,它绝对不会收到来自内核的 SIGHUP 信号,许多守护进程因此把这个信号作为来自系统管理员的一个通知,表示其配置文件已发生改动,守护进程应该重新读取其配置文件。同理还有 SIGINTSIGWINCH 等等

    改进时间服务器

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    int main(int argc, char** argv) {
        int listenfd, connfd;
        socklen_t addrlen, len;
        struct sockaddr* cliaddr;
        char buff[MAXLINE];
        time_t ticks;
    
      	// 如果有一些显而易见的错误,则立即抛出,而不是在日志中抛出
        if (argc < 2 || argc > 3)
            err_quit("usage: daytimetcpsrv2 [ <host> ] <service or port>");
    
        // 使用我们的函数启动
        daemon_init(argv[0], 0);
    
        if (argc == 2)
            listenfd = Tcp_listen(NULL, argv[1], &addrlen);
        else
            listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
    
        cliaddr = Malloc(addrlen);
    
        for (;;) {
            len = addrlen;
            connfd = Accept(listenfd, cliaddr, &len);
            err_msg("connection from %s", Sock_ntop(cliaddr, len));
    
            ticks = time(NULL);
            snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
            Write(connfd, buff, strlen(buff));
    
            Close(connfd);
        }
    }
    

    日志消息

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    syslogd

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    Unix 系统中的 syslogd 守护进程通常由某个系统初始化脚本启动,并且在系统工作期间一直运行

    启动的步骤:

    1. 读取配置:通常为 /etc/syslog.conf ,配置了对消息的处理
    2. 创建Unix域数据报套接字:给他绑定路径名 /var/run/log (或 /dev/log
    3. 创建一个 UDP 套接字:绑定端口 514
    4. 打开路径名 /dev/klog:来自内核中的任何出错消息从这个“设备”输入
    5. 监听:调用 select,监听 2 ~ 4 步骤的描述符
      • 如果收到消息,读入并按照配置进行处理
      • 如果收到 SIGHUP 信号,则重新读取配置文件 (这让我想到了 NGINX 重载配置文件时服务无需暂停)

    较新的 syslogd 实现禁止创建 UDP 套接字,因为这样可能会让系统遭到 DOS 攻击,其文件系统可能被填满,从而占满内存空间,或挤掉合法的日志消息

    我们一般不会直接向其发送消息,而是通过 syslog 函数写入日志!

    syslog

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    守护进程记录消息可以使用 syslog 函数:

    #include <syslog.h>
    
    void syslog(int priority, // 优先级
               const char *message, // 消息
               ...)
    

    参数解释:

    • priority:好理解,大多日志都有日志级别的功能
    • facility:用于标识发送进程类型(函数的参数列表中没有?因为这个要和 priority 用逻辑或使用)
    • message:消息内容,类似 printf,不同的是其增加了 %m 规范,用以输出当前 errno 值对应的错误信息

    案例

    syslog(LOG_INFO|LOG_LOCAL2, "rename(%s, %s): %m", file1, fil)
    

    /etc/syslog.conf

    kern.* 				/dev/debug					# 内核的所有消息发送到控制台
    local7.debug 	/var/log/cisco.log	# 来自 local7 的所有消息添加到文件 cisco.log 的尾部
    

    一些细节

    • 当 syslog 被应用程序首次调用时,它创建一个 Unix 域数据报套接字,然后调用 connect 连接到由 syslogd 守护进程创建的 Unix 域数据报套接字的众所周知路径名(如 /var/run/log )这个套接字一直保持打开,直到进程终止
    • 可以用 openlogcloselog 来操作上述步骤,在首次调用 syslog 前调用 openlog,不需要发送日志时调用 closelog

    openlog 和 closelog

    #include <syslog.h>
    void openlog(const char* ident, // 日志的前缀,通常是程序名
                 int options, 			// 可选值
                 int facility);			// 设置默认的打印设施的值
    void closelog(void);
    
    options 说明
    LOG_CONS 若无法发送到 syslogd 则登记到控制台
    LOG_NDELAY openlog 默认是懒汉加载,这个选项设置不延迟打开,立刻创建套接字
    LOG_PERROR 既发送到 syslogd 守护进程,又登记到标准错误输出
    LOG_PID 随每个日志消息等级进程 ID

    inetd 守护进程

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    引入 inetd

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    原来的系统服务模型

    Unix 上的很多服务,如 SSH、FTP、Telnet 等,我们都可以把它当作一个 Server 端

    在系统启动的过程中,这些进程从 /etc/rc 文件中启动,而且每个进程都执行几乎相同的启动任务:

    1. 创建一个套接字,绑定端口
    2. 等待连接或数据报的到来
    3. 派生子进程,子进程提供服务,父进程继续监听

    这种方式的缺点

    1. 所有这些守护进程含有几乎相同的启动代码
    2. 每个守护进程在进程表中占据一个表项,然而大多数时间他们处于睡眠状态

    inted 守护进程

    为了解决这种问题,4.3BSD 提供一个因特网超级服务器(即 inetd 守护进程):

    1. 通过由 inetd 处理普通守护进程的大部分启动细节以简化守护进程的编写,这么一来每个服务器不再有调用 daemon_init 函数的必要
    2. 单个进程(inetd)就能为多个服务等待外来的客户请求,以取代每个服务器一个进程的做法

    inetd 配置文件

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    inetd 使用前文提到的方法把自己变成一个守护进程,然后读取并处理自己的配置文件,通常在 /etc/inetd.conf ,该文件包括如下内容:

    字段 说明
    service-name 必须在 /etc/services 文件中定义
    socket-type stream(TCP)、dgram(UDP)
    protocol 必须在 /etc/protocols 文件中定义:tcp或udp
    wait-flag 对于 TCP 一般为 nowait,对于 UDP 一般为 wait
    login-name 来自 /etc/passwd 的用户名,一般为 root
    server-program 调用 exec 指定的完整路径名
    server-program-arguments 调用 exec 指定的命令行参数

    inetd 工作流程

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    其工作流程如下:

    1. 读入配置文件,为每个服务创建一个合适的套接字

    2. 为每个套接字调用 bind,指定端口和通配地址

      端口号可以通过 getservbyname 获取,用配置文件中的 service-name 和 protocal 字段做参数

    3. 对于每个 TCP 套接字,调用 listen 以接受外来的连接请求,对于 UDP 则不执行

    4. 创建完所有套接字后,调用 select 等待其中任何一个套接字变得可读

    对于 TCP:

    1. 当 select 返回可读后,如果该套接字是一个 TCP 套接字,而且其 wait-flag 为 nowait,则调用 accept 接受这个新连接
    2. inetd 守护进程调用 fork 派生进程,并由子进程处理服务请求,与前面的并发服务器类似,关闭相应的描述符
    3. 子进程关闭除了要处理的套接字描述符外的所有的描述符,并根据配置文件,切换到相应的用户,用 exec 执行相应的操作

    如果设置为 wait,对于 TCP 来说,父进程会用 FD_CLR 禁止这个套接字,保存子进程 ID,当子进程终止(SIGCHILD)后才继续监听

    对于 UDP:

    因为数据报服务器只有一个套接字,所以只能一个一个来处理,也就是说通过接受子进程终止的 SIGCHLD 信号后才继续监听

    因为假如 fork 后一个子进程,而父进程先于该子进程再次执行,则会由于还没读取数据而再次触发 select 的事件,从而再次 fork 一个无用的子进程

    xinetd

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    xinetd 提供与 inetd 一致的基本服务,不过还提供了数目众多的其他特性,包括根据客户的地址登记、接受或拒绝连接的选项等等

    daemond_inetd

    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
    本文信息本文信息防爬虫替换信息
    作者网站LYMTICShttps://lymtics.top
    作者LYMTICS(樵仙)https://lymtics.top
    联系方式me@tencent.mlme@tencent.ml
    原文标题《Unix 网络编程》13:守护进程和 inet 超级服务器《Unix 网络编程》13:守护进程和 inet 超级服务器
    原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
    • 如果您访问本文的链接并非如上地址,则可能是爬取作者的文章,建议返回原站阅读,谢谢您的支持
    • 原文会不断地更新和完善排版和样式会更加适合阅读,并且有相关配图
    ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

    这个函数的唯一作用就是为错误处理函数设置 daemon_proc 标志,使得运行信息输出在日志中

    extern int daemon_proc; /* defined in error.c */
    
    void daemon_inetd(const char* pname, int facility) {
        daemon_proc = 1; /* for our err_XXX() functions */
        openlog(pname, LOG_PID, facility);
    }
    

    修改后的服务器代码:

    int main(int argc, char** argv) {
        socklen_t len;
        struct sockaddr* cliaddr;
        char buff[MAXLINE];
        time_t ticks;
    
        daemon_inetd(argv[0], 0);
    
        cliaddr = Malloc(sizeof(struct sockaddr_storage));
        len = sizeof(struct sockaddr_storage);
        Getpeername(0, cliaddr, &len);
        err_msg("connection from %s", Sock_ntop(cliaddr, len));
    
        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(0, buff, strlen(buff));
    
        Close(0); /* close TCP connection */
        exit(0);
    }
    
    • 我们用描述符 0 指代被接受的 TCP 连接
    • 因为这个程序针对每一个连接启动一次,所以不需要无限循环

    为了启动这个程序,我们需要在 /etc/services 文件中添加:

    mydaytime			9999/tcp
    

    /etc/inetd.conf 中添加:(在题主的电脑里就只有 xinetd.conf 了)

    mydaytime stream tcp nowait andy /foo/bar/daytimetcpsrv3 daytimetcpsrv3
    

    然后给 inetd 发送一个 SIGHUP 信号,告知它重新读取配置文件


    __EOF__

  • 本文作者: LYMTICS
  • 本文链接: https://www.cnblogs.com/lymtics/p/16341341.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    【JVM调优实战100例】01——JVM的介绍与程序计数器
    多环境镜像晋级/复用最佳实践
    软件测试基本流程有哪些?北京专业第三方软件检测机构安利
    【第五部分 | JS WebAPI】3:DOM 节点操作
    【JVM】垃圾回收
    安装vue-router及报错问题
    Android 实战项目:找回密码
    立体式校验保护,让你的系统避免 90% 以上的 bug
    【Python】Jupyter Notebook的安装与基本使用方法
    5个精美的wordpress中文企业主题模板
  • 原文地址:https://www.cnblogs.com/lymtics/p/16341341.html