【Linux网络编程六】服务器守护进程化Daemon

【Linux网络编程六】服务器守护进程化Daemon

  • 一.背景知识:前台与后台
  • 二.相关操作
  • 三.Linux的进程间关系
  • 四.自成会话
  • 五.守护进程四步骤
  • 六.服务器守护进程化

一.背景知识:前台与后台

在这里插入图片描述

核心知识就是一个用户在启动Linux时,都会给一个session会话,这个会话里会存在一个前台进程,和多个后台进程。

在这里插入图片描述

二.相关操作

在这里插入图片描述

三.Linux的进程间关系

Linux中的进程之间的关系,不仅仅是相互独立的,还可以过程进程组,进程组的组长就是第一个进程的pid。
在这里插入图片描述

四.自成会话

在这里插入图片描述
当一个任务以后台进程在会话中执行,然后我们将会话关闭,重新启动一个会话,将会发现这个任务虽然还存在,但其实已经不再是原先的那个任务了,因为它的父进程bash已经退出,它被系统自动领养了。(它原来的会话是会被记录下来的)

所以进程组是会收到用户的登录和退出的影响。进程组就代表着一个任务,也就是任务是会收到用户的退出影响,用户一旦退出,那么该任务就不再属于你了,也就是该任务已经没有了。你把会话都关闭了,那么里面的所有任务都会不存在了。

这里我想说的就是我们想让一个任务一直执行,不受用户的登录和退出影响,就必须使用守护进程!
守护进程的核心就是自成会话。
在这里插入图片描述
在这里插入图片描述
因为创建新会话的进程不能是进程组里的组长,所以我们就直接让当前进程创建子进程,然后再让当前进程直接退出,让子进程创建会话。

五.守护进程四步骤

守护进程四步骤:①忽略其他信号②自成会话③更改工作目录④重定向标准输入与输出。
在这里插入图片描述
因为自成会话后,新会话就不再与终端有联系了,就不需要标准输出和标准输入和标准错误了。
而打印日志可以直接往文件里输入。

其实系统中提供了守护进程化的接口调用:
在这里插入图片描述

六.服务器守护进程化

其实守护进程的本质就是后台进程,服务器一旦启动了守护进程化,那么就不会受用户的退出影响,就会一直在运行。

//守护进程
#pragma once#include <signal.h>
#include <unistd.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="")
{//第一步忽略其他异常信号,防止被信号杀死signal(SIGCLD,SIG_IGN);signal(SIGPIPE,SIG_IGN);signal(SIGSTOP,SIG_IGN);//第二步将自己变成新的会话,不受其他会话管理if(fork()>0)exit(0);//让孙子进程来创建新的会话,因为自成组长的进程不能创建新会话setsid();//让使用该函数的进程创建新的会话,并属于该会话//第三步更改当前进程的路径//根据需要传入不同的路径就更改到不同路径下if(!cwd.empty()){chdir(cwd.c_str());}//第四步,将标准输入,标准输出,标志错误,重定向到垃圾桶文件里,新的会话不再与终端关联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 <cstring>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include "Log.hpp"
#include "TASK.hpp"
#include "ThreadPool.hpp"
#include "Daemon.hpp"
Log lg;const std::string defaultip="0.0.0.0";
const int defaultfd=-1;
int backlog=10;//一般不要设置太大
enum 
{SockError=2,BindError,AcceptError,
};
class Tcpserver;class ThreadData
{
public:ThreadData(int &fd,const std::string& ip,uint16_t &port,Tcpserver* svr):_sockfd(fd),_ip(ip),_port(port),_svr(svr){}
public:  int _sockfd;std::string _ip;uint16_t _port;Tcpserver* _svr;
};class Tcpserver
{
public:Tcpserver(const uint16_t &port,const std::string &ip=defaultip):_listensock(-1),_port(port),_ip(ip){}void Init(){//服务器端启动之前创建套接字,绑定。//一开始的这个套接字是属于监听套接字_listensock=socket(AF_INET,SOCK_STREAM,0);if(_listensock<0){lg(Fatal,"sock create errno:%d errstring:%s",errno,strerror(errno));exit(SockError);}//创建套接字成功lg(Info,"sock create sucess 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);//填充完毕,真正绑定if((bind(_listensock,(struct sockaddr*)&local,sizeof(local)))<0){lg(Fatal,"bind errno:%d errstring:%s",errno,strerror(errno));exit(BindError);}lg(Info,"bind socket success listensock:%d",_listensock);//绑定成功//udp中绑定成功后就可以进行通信了,但tcp与udp不同。tcp是面向连接的,在通信之前//需要先获取新连接,获取到新连接才能进行通信。没有获取连接那么就要等待连接,等待新连接的过程叫做监听,监听有没有新连接。//需要将套接字设置成监听状态listen(_listensock,backlog);//用来监听,等待新连接,只有具备监听状态才能识别到连}static void* Routine(void *args)//静态成员函数无法使用成员函数,再封装一个服务器对象{//子线程要和主线程分离,主线程不需要等待子线程,直接回去重新获取新连接pthread_detach(pthread_self());ThreadData* td=static_cast<ThreadData*>(args);//子线程用来服务客户端td->_svr->Service(td->_sockfd,td->_ip,td->_port);delete td;return nullptr;}void Run(){Daemon();signal(SIGPIPE,SIG_IGN);//防止服务端往一个已经关闭的文件描述符里写入,忽略带操作系统发送的信号//一启动服务器,就将线程池中的线程创建ThreadPool<TASK>::GetInstance()->Start();//单例对象//静态函数,通过类域就可以使用lg(Info,"tcpserver is running");while(true){struct sockaddr_in client;socklen_t len=sizeof(client);//将套接字设置成监听状态后,就可以获取新连接int sockfd=accept(_listensock,(struct sockaddr*)&client,&len);//获取从监听套接字那里监听到的连接。然后返回一个新套接字,通过这个套接字与连接直接通信,而监听套接字继续去监听。if(sockfd<0){lg(Fatal,"accept error,errno: %d, errstring: %s",errno,strerror(errno));exit(AcceptError);}//获取新连接成功//将客户端端网络信息带出来uint16_t clientport=ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET,&client.sin_addr,clientip,sizeof(clientip));//根据新连接进行通信lg(Info,"get a new link...sockfd: %d,clientip: %s,clientport: %d",sockfd,clientip,clientport);//构建任务TASK t(sockfd,clientip,clientport); //将任务放进线程池里,线程就会到线程池里去执行任务。ThreadPool<TASK>::GetInstance()->Push(t);}}void Service(int &sockfd,const std::string &clientip,uint16_t &clientport){char inbuffer[1024];while(true){ssize_t n=read(sockfd,inbuffer,sizeof(inbuffer));if(n>0){inbuffer[n]=0;std::cout<<"client say# "<<inbuffer<<std::endl;//加工处理一下std::string echo_string="tcpserver加工处理数据:";echo_string+=inbuffer;//将加工处理的数据发送会去write(sockfd,echo_string.c_str(),echo_string.size());}else if(n==0)//如果没有用户连接了,那么就会读到0.服务器端也就不要再读了{lg(Info,"%s:%d quit, server close sockfd: %d",clientip.c_str(),clientport,sockfd);break;}else{lg(Fatal,"read errno: %d, errstring: %s",errno,strerror(errno));}}}~Tcpserver(){}private:int _listensock;//监听套接字只有一个,监听套接字用来不断获取新的连接。返回新的套接字std::string _ip;uint16_t _port;
};
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>void Usage(std::string proc)
{std::cout<<"\n\rUsage: "<<proc<<" port[1024+]\n"<<std::endl;
}
//./tcpclient ip port
int main(int args,char* argv[])
{if(args!=3){Usage(argv[0]);exit(1);}std::string serverip=argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;socklen_t len=sizeof(server);server.sin_family=AF_INET;server.sin_port=htons(serverport);inet_pton(AF_INET,serverip.c_str(),&server.sin_addr);while(true){//创建套接字int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){std::cout<<"create sockfd err "<<std::endl;}//创建套接字成功,创建完套接字后该干什么?//连接服务器端的套接字,所以客户端用户需要知道服务器端的网络信息的int cnt=10;bool isreconnect=false;do{ int n=connect(sockfd,(struct sockaddr*)&server,len);if(n<0)//服务器关闭了,肯定会连接失败{isreconnect=true;cnt--;std::cout<<"connect sock err...,cnt: "<<cnt<<std::endl;sleep(12);}else//重连成功了{break;}}while(cnt&&isreconnect);//连接成功//连接成功后,就可以直接通信了,就可以直接给对方写消息了。if(cnt==0){std::cerr<<"user offline.."<<std::endl;break;//用户直接不玩了}std::string message;std::cout<<"Please enter#";getline(std::cin,message);//往套接字里写int n=write(sockfd,message.c_str(),message.size());if(n<0)//服务器端会将该套接字关闭,然后就写不进去了。需要重新创建套接字连接{std::cerr<<"write error..."<<std::endl;continue;}char outbuffer[1024];//接收服务器发送的加工处理消息n=read(sockfd,outbuffer,sizeof(outbuffer));if(n>0){outbuffer[n]=0;std::cout<<outbuffer<<std::endl;}close(sockfd);}return 0;}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/685051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java毕业设计-基于springboot的学院物资管理系统-第73期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学院物资管理系统&#xff1a;前端thymeleaf、jquery、layui&#xff0c;后端 maven、springmvc、spring、mybatis&#xff0c;有配套报告文档&#xff…

【动态规划】【记忆化搜索】【状态压缩】1681. 最小不兼容性

作者推荐 【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 本文涉及知识点 动态规划汇总 状态压缩 记忆化搜索 1681. 最小不兼容性 给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中&#xff0c;使得同一…

指针的经典笔试题

经典的指针试题&#xff0c;让你彻底理解指针 前言 之前对于指针做了一个详解&#xff0c;现在来看一些关于指针的经典面试题。 再次说一下数组名 数组名通常表示的都是首元素的地址&#xff0c;但是有两个意外&#xff0c;1.sizeof&#xff08;数组名&#xff09;这里数组名…

如何在JavaScript中使用大于和小于运算符

在你的 JavaScript 程序中&#xff0c;你经常需要比较两个值&#xff0c;以确定一个是否大于另一个或小于另一个。这就是大于和小于运算符派上用场的地方。 在本文中&#xff0c;我们将通过代码示例更详细地介绍如何使用这些运算符。 &#xff08;本文内容参考&#xff1a;ja…

rabbitmq自用记录

参考博客RabbitMq安装与使用&#xff08;mac&#xff09;高效总结&#xff08;亲测&#xff09;_mac 安装rabbitmq 服务端口-CSDN博客 启动服务 这里提前把redis服务也启动了 这里看到前端更改数据,后端进行日志打印 登录后访问rabbitmq网址

java 线程安全介绍

所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型&#xff0c;要解决两个主要的问题&#xff1a;可见性和有序性。 那么&#xff0c;何谓可见性&#xff1f; 多个线程之间是不能互相传递数据通信的&#xff0c;它们之间的沟通只能通过共享变量…

MinIO 和 Apache Tika:文本提取模式

Tl;dr: 在这篇文章中&#xff0c;我们将使用 MinIO Bucket Notifications 和 Apache Tika 进行文档文本提取&#xff0c;这是大型语言模型训练和检索增强生成 LLM和RAG 等关键下游任务的核心。 前提 假设我想构建一个文本数据集&#xff0c;然后我可以用它来微调 LLM.为了做…

爬虫之牛刀小试(十):爬取某宝手机商品的销量,价格和店铺

首先淘宝需要登录&#xff0c;这一点如果用selenium如何解决&#xff0c;只能手动登录&#xff1f;如果不用selenium&#xff0c;用cookies登录也可。但是验证码又是一个问题&#xff0c;现在的验证码五花八门&#xff0c;难以处理。 我们回到正题&#xff0c;假设你已经登录上…

计算机设计大赛 深度学习YOLO图像视频足球和人体检测 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov5算法5 数据集6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习YOLO图像视频足球和人体检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非…

一览大模型长文本能力

前言 如今的大模型被应用在各个场景&#xff0c;其中有些场景则需要模型能够支持处理较长文本的能力(比如8k甚至更长)&#xff0c;其中已经有很多开源或者闭源模型具备该能力比如GPT4、Baichuan2-192K等等。 那关于LLM的长文本能力&#xff0c;目前业界通常都是怎么做的&…

2024年腾讯云4核8G12M服务器性能测评,适合哪些使用场景?

腾讯云4核8G服务器适合做什么&#xff1f;搭建网站博客、企业官网、小程序、小游戏后端服务器、电商应用、云盘和图床等均可以&#xff0c;腾讯云4核8G服务器可以选择轻量应用服务器4核8G12M或云服务器CVM&#xff0c;轻量服务器和标准型CVM服务器性能是差不多的&#xff0c;轻…

阿里云BGP多线精品EIP香港CN2线路低时延,价格贵

阿里云香港等地域服务器的网络线路类型可以选择BGP&#xff08;多线&#xff09;和 BGP&#xff08;多线&#xff09;精品&#xff0c;普通的BGP多线和精品有什么区别&#xff1f;BGP&#xff08;多线&#xff09;适用于香港本地、香港和海外之间的互联网访问。使用BGP&#xf…

【实战】二、Jest难点进阶(一) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(五)

文章目录 一、Jest 前端自动化测试框架基础入门二、Jest难点进阶1.snapshot 快照测试 学习内容来源&#xff1a;Jest入门到TDD/BDD双实战_前端要学的测试课 相对原教程&#xff0c;我在学习开始时&#xff08;2023.08&#xff09;采用的是当前最新版本&#xff1a; 项版本babe…

jmeter遇到连接数据库的问题

jmeter连接mysql或者oracle简单&#xff0c;但是连接过inceptor吗&#xff1f; 上货 1、下载驱动inceptor 5.1.2.jar包 2、在添加驱动那里导入 3、在JBC request中的写法 PS:没什么可说的

【C++】类和对象(五)友元、内部类、匿名对象

前言&#xff1a;前面我们说到类和对象是一个十分漫长的荆棘地&#xff0c;今天我们将走到终点&#xff0c;也就是说我们对于&#xff23;算是正式的入门了。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习 &…

嵌入式中全面解析 SPI 通信协议方法

SPI 的英文全称为 Serial Peripheral Interface&#xff0c;顾名思义为串行外设接口。SPI 是一种同步串行通信接口规范&#xff0c;主要应用于嵌入式系统中的短距离通信。该接口由摩托罗拉在20世纪80年代中期开发&#xff0c;后发展成了行业规范。 SPI 是一种高速的、全双工的…

算法沉淀——优先级队列(堆)(leetcode真题剖析)

算法沉淀——优先级队列 01.最后一块石头的重量02.数据流中的第 K 大元素03.前K个高频单词04.数据流的中位数 优先队列&#xff08;Priority Queue&#xff09;是一种抽象数据类型&#xff0c;它类似于队列&#xff08;Queue&#xff09;&#xff0c;但是每个元素都有一个关联的…

嵌入式Linux平台大文件生成以及处理方法

在日常工作中&#xff0c;为了验证某些场景下的功能&#xff0c;经常需要人为构造一些大文件进行测试&#xff0c;有时需要用大文件来测试下载速度&#xff0c;有时需要用大文件来覆盖磁盘空间&#xff1b;偶尔会看到一些网络博文会教大家如何构造大文件&#xff1b;但是当需要…

杨中科 ASP.NET DI综合案例

综合案例1 需求说明 1、目的:演示DI的能力; 2、有配置服务、日志服务&#xff0c;然后再开发一个邮件发送器服务。可以通过配置服务来从文件、环境变量、数据库等地方读取配置&#xff0c;可以通过日志服务来将程序运行过程中的日志信息写入文件、控制台、数据库等。 3、说明…

第三百四十九回

文章目录 1. 概念介绍2. 原理与方法2.1 知识对比2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"加密包crypto"相关的内容&#xff0c;本章回中将介绍characters包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 在项目中会遇到获取字…