您的位置:首页 > 文旅 > 旅游 > javascript权威指南_网页设计psd_内容营销平台有哪些_深圳广告投放公司

javascript权威指南_网页设计psd_内容营销平台有哪些_深圳广告投放公司

2024/12/23 8:36:34 来源:https://blog.csdn.net/m0_53830389/article/details/144333465  浏览:    关键词:javascript权威指南_网页设计psd_内容营销平台有哪些_深圳广告投放公司
javascript权威指南_网页设计psd_内容营销平台有哪些_深圳广告投放公司

目录

一、守护进程的定义与特点

1、定义

2、特点

二、守护进程的原理

三、守护进程与会话(Session)的关系

四、C++实现守护进程

     守护进程(Daemon Process)是一个在后台运行、通常不与用户直接交互的进程。守护进程是操作系统中非常重要的一部分,常见的应用包括系统日志、网络服务、数据库管理等。在这篇博客中,我们将详细探讨守护进程的原理、如何与会话管理联系,并通过C++实现一个简单的守护进程。将服务器守护进程化的主要目的是确保服务器在后台持续运行,并在意外崩溃或重启后自动恢复。这样可以使服务在没有人工干预的情况下长期稳定运行,并减少系统管理的复杂度。

一、守护进程的定义与特点

1、定义

守护进程是一个没有终端控制的进程,它通常在系统启动时启动,独立于任何用户会话(session),并且在后台持续运行。守护进程的特点是它不依赖于用户的输入输出,运行时不会产生终端交互。

2、特点

  • 后台运行:守护进程通常在操作系统启动时启动,或者在用户登录后由系统服务启动,并在后台持续运行。
  • 无终端:守护进程不与任何终端或用户会话关联,它通常不与标准输入输出(stdin, stdout, stderr)相关联。
  • 独立性:守护进程与用户的登录会话是独立的,它在后台静静运行,执行系统级任务,如日志记录、定时任务、文件清理等。
  • 父进程为init进程:守护进程在系统启动时由父进程(通常是init进程)启动,运行时不会退出。
  • PID(进程ID):守护进程的PID是由操作系统分配的,它通常会被写入到某个文件中以供后续管理和终止。

二、守护进程的原理

守护进程是通过脱离控制终端、使自己成为一个独立的后台进程来实现的。这是通过几个步骤实现的:

  1. 创建子进程:守护进程首先会创建一个子进程,父进程退出,子进程继续执行,这样可以让守护进程避免与任何用户会话或终端直接交互。

  2. 创建新的会话(Session):守护进程通常会调用 setsid() 系统调用创建一个新的会话,成为该会话的首进程。新会话的创建意味着它不再与原始的控制终端和进程组相关联。

  3. 改变工作目录:守护进程通常会调用 chdir() 来更改工作目录。为了避免占用终端的目录,守护进程通常会将工作目录更改为 /

  4. 关闭文件描述符:守护进程还会关闭与终端相关的文件描述符,包括标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。通常会将它们重定向到 /dev/null,以防止输出到终端。

  5. 忽略信号:守护进程会设置适当的信号处理,避免因收到如SIGHUP等信号导致进程退出。

void Daemon(const std::string &cwd = "")
{// 1. 忽略其他异常信号 signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2. 将自己变成独立的会话if (fork() > 0)//>0说明是父进程,让父进程直接退出exit(0);setsid(); //子进程// 3. 更改当前调用进程的工作目录if (!cwd.empty())chdir(cwd.c_str());// 4. 标准输入,标准输出,标准错误重定向至/dev/null 垃圾桶int fd = open(nullfile.c_str(), O_RDWR);if(fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}
}

三、守护进程与会话(Session)的关系

会话(Session)是与进程、终端和进程组密切相关的概念。会话的作用是管理一组相关的进程。

  1. 会话的创建:每个登录的用户会话都有一个会话ID(Session ID),一个会话可以有多个进程组(Process Group),而每个进程组中的进程共享同一个控制终端。

  2. 脱离控制终端:守护进程通过 setsid() 系统调用来脱离当前会话及其控制终端,成为一个新的会话的首进程。这样,守护进程就不再与任何终端关联,它可以自由地运行而不受用户的控制。

  3. 控制终端:一旦守护进程创建了新的会话并成为首进程,它就不再与任何控制终端关联。控制终端通常与用户的登录会话相关联,但守护进程会断开这一关系,避免终端输入或输出干扰其运行。

  4. 进程组与信号处理:会话中的进程通常共享进程组,而进程组的控制由会话首进程管理。守护进程通常会设置信号处理机制,使其能够管理来自进程组的信号。


四、C++实现守护进程

#pragma once#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string nullfile = "/dev/null";void Daemon(const std::string &cwd = "")
{// 1. 忽略其他异常信号 signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2. 将自己变成独立的会话if (fork() > 0)//>0说明是父进程,让父进程直接退出exit(0);setsid(); //子进程// 3. 更改当前调用进程的工作目录if (!cwd.empty())chdir(cwd.c_str());// 4. 标准输入,标准输出,标准错误重定向至/dev/null 垃圾桶int fd = open(nullfile.c_str(), O_RDWR);if(fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}
}
#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <signal.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10; // 但是一般不要设置的太大
extern Log lg;enum
{UsageError = 1,SocketError,BindError,ListenError,
};class TcpServer;class ThreadData
{
public:ThreadData(int fd, const std::string &ip, const uint16_t &p, TcpServer *t): sockfd(fd), clientip(ip), clientport(p), tsvr(t){}
public:int sockfd;std::string clientip;uint16_t clientport;TcpServer *tsvr;
};class TcpServer
{
public:TcpServer(const uint16_t &port, const std::string &ip = defaultip) : listensock_(defaultfd), port_(port), ip_(ip){}void InitServer(){listensock_ = socket(AF_INET, SOCK_STREAM, 0);if (listensock_ < 0){lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));exit(SocketError);}lg(Info, "create socket success, listensock_: %d", listensock_);int opt = 1;setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_);inet_aton(ip_.c_str(), &(local.sin_addr));// local.sin_addr.s_addr = INADDR_ANY;if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));exit(BindError);}lg(Info, "bind socket success, listensock_: %d", listensock_);// Tcp是面向连接的,服务器一般是比较“被动的”,服务器一直处于一种,一直在等待连接到来的状态if (listen(listensock_, backlog) < 0){lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));exit(ListenError);}lg(Info, "listen socket success, listensock_: %d", listensock_);}void Start(){Daemon();ThreadPool<Task>::GetInstance()->Start();// for fork();// signal(SIGCHLD, SIG_IGN);lg(Info, "tcpServer is running....");for (;;){// 1. 获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);if (sockfd < 0){lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //?continue;}uint16_t clientport = ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));// version 4 --- 线程池版本Task t(sockfd, clientip, clientport);ThreadPool<Task>::GetInstance()->Push(t);}}~TcpServer() {}private:int listensock_;uint16_t port_;std::string ip_;
};

表示服务已经启动

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com