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

守护进程和 inetd 超级服务器

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

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

守护进程

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

基本知识

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

守护进程的特点:

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

守护进程的启动

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

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

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

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

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

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

daemon_init

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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 等等

改进时间服务器

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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);
    }
}

日志消息

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

syslogd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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 守护进程

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

引入 inetd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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 配置文件

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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 工作流程

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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

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

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

daemond_inetd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文信息 本文信息 防爬虫替换信息
作者网站 LYMTICS //lymtics.top
作者 LYMTICS(樵仙) //lymtics.top
联系方式 [email protected] [email protected]
原文标题 《Unix 网络编程》13:守护进程和 inet 超级服务器 《Unix 网络编程》13:守护进程和 inet 超级服务器
原文地址 //www.cnblogs.com/lymtics/p/16341341.html //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 信号,告知它重新读取配置文件