【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;}
相关文章:

【Linux网络编程六】服务器守护进程化Daemon
【Linux网络编程六】服务器守护进程化Daemon 一.背景知识:前台与后台二.相关操作三.Linux的进程间关系四.自成会话五.守护进程四步骤六.服务器守护进程化 一.背景知识:前台与后台 核心知识就是一个用户在启动Linux时,都会给一个session会话&a…...

MySQL之json数据操作
1 MySQL之JSON数据 总所周知,mysql5.7以上提供了一种新的字段格式json,大概是mysql想把非关系型和关系型数据库一口通吃,所以推出了这种非常好用的格式,这样,我们的很多基于mongoDB的业务都可以用mysql去实现了。当然…...

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(5)数据管理
今天学习了数据管理,以及数据管理和数据治理的区别和联系。 数据管理:利用计算机硬件和软件技术对数据进行有效的收集、存储、处理和应用的过程其目的在于充分有效地发挥数据的作用。 实现数据有效管理的关键是数据组织。 数据管理和数据治理的区别&am…...

Linux满载CPU和运行内存的方法
查询CPU详细信息命令如下: 查看物理CPU型号: cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c查看物理CPU个数 cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l查看每个物理CPU中core的个数(即核数) cat /proc/cpuinfo…...

每日五道java面试题之java基础篇(九)
目录: 第一题 你们项⽬如何排查JVM问题第二题 ⼀个对象从加载到JVM,再到被GC清除,都经历了什么过程?第三题 怎么确定⼀个对象到底是不是垃圾?第四题 JVM有哪些垃圾回收算法?第五题 什么是STW? 第…...

spring @Transactional注解参数详解
事物注解方式: Transactional 当标于类前时, 标示类中所有方法都进行事物处理 , 例子: 1 Transactional public class TestServiceBean implements TestService {}当类中某些方法不需要事物时: Transactional public class TestServiceBean implements TestService {private…...

D - 串结构练习——字符串连接
串结构练习——字符串连接 Description 给定两个字符串string1和string2,将字符串string2连接在string1的后面,并将连接后的字符串输出。 连接后字符串长度不超过110。 Input 输入包含多组数据,每组测试数据包含两行,第一行代表s…...

什么样的服务器是高性能服务器?
首先,高性能服务器应具备高处理能力。随着业务的不断扩展和数据量的爆炸性增长,高性能服务器需要具备强大的计算能力,能够快速处理各种复杂的业务和数据。这要求高性能服务器采用先进的处理器技术,如多核处理器、GPU加速等&#x…...

数学建模【线性规划】
一、线性规划简介 线性规划通俗讲就是“有限的资源中获取最大的收益”(优化类问题)。而且所有的变量关系式都是线性的,不存在x、指数函数、对数函数、反比例函数、三角函数等。此模型要优化的就是在一组线性约束条件下,求线性目标…...

ChatGPT的大致原理
国外有个博主写了一篇博文,名字叫TChatGPT: Explained to KidsQ」, 直译过来就是,给小孩子解释什么是ChatGPT。 因为现实是很多的小孩子已经可以用父母的手机版ChatGPT玩了 ,ChatGPT几乎可以算得上无所不知,起码给小孩…...

蓝桥杯备赛_python_BFS搜索算法_刷题学习笔记
1 bfs广度优先搜索 1.1 是什么 1.2怎么实现 2案例学习 2.1.走迷宫 2.2.P1443 马的遍历 2.3. 九宫重排(看答案学的,实在写不来) 2.4.青蛙跳杯子(学完九宫重排再做bingo) 2.5. 长草 3.总结 1 bfs广度优先搜索 【P…...

轮播图的五种写法(原生、vue2、vue3、react类组件,react函数组件)
轮播图效果是一种在网页或应用程序中展示多张图片或内容的方式,通常以水平或垂直的方式循环播放。本文使用原生、vue2、vue3、react类组件,react函数组件五种写法实现了简单的轮播图效果,需要更多轮播效果需要再增加样式或者动画。 淡入淡出效果:每张图片渐渐淡入显示,然后…...

【MySQL】高度为2和3时B+树能够存储的记录数量的计算过程
文章目录 题目答案高度为2时的B树高度为3时的B树总结 GPT4 对话过程 题目 InnoDB主键索引的Btree在高度分别为 2 和 3 时,可以存储多少条记录? 答案 高度为2时的B树 计算过程: 使用公式 ( n 8 ( n 1 ) 6 16 1024 ) (n \times 8 …...

软件著作书 60页代码轻松搞定!(附exe和代码)
最近做了一个软件,准备去申请软件著作书,看着那60页的文档,确实难搞,不过幸好会用一点点python,就自己用python写了一个读取所有文件代码的程序,使用起来也很简单,过来分享一下 链接࿱…...

阿里文档类图像的智能识别,文档分类自定义分类器
阿里云文档类图像智能识别服务为用户提供了强大的文档处理能力,可以将文档图像中的文本内容、表格数据和结构化信息自动识别并提取出来。而自定义分类器则允许用户根据自己的需求,训练出更适合自己场景的文档分类模型。本文将详细介绍阿里云文档类图像智…...

256.【华为OD机试真题】会议室占用时间(区间合并算法-JavaPythonC++JS实现)
🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目二.解题思路三.题解代码Python题解代码JAVA题解…...

人工智能学习与实训笔记(三):神经网络之目标检测问题
人工智能专栏文章汇总:人工智能学习专栏文章汇总-CSDN博客 目录 三、目标检测问题 3.1 目标检测基础概念 3.1.1 边界框(bounding box) 3.1.2 锚框(Anchor box) 3.1.3 交并比 3.2 单阶段目标检测模型YOLOv3 3.2…...

SSM框架,Spring-ioc的学习(下)
拓展:在xml文件中读取外部配置文件 例:若要导入外部配置文件jdbc.properties <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"<http://www.springframework.org/schema/beans>"xmlns:xsi"&l…...

【AIGC】Stable Diffusion的模型微调
为什么要做模型微调 模型微调可以在现有模型的基础上,让AI懂得如何更精确生成/生成特定的风格、概念、角色、姿势、对象。Stable Diffusion 模型的微调方法通常依赖于您要微调的具体任务和数据。 下面是一个通用的微调过程的概述: 准备数据集…...

VNCTF 2024 Web方向 WP
Checkin 题目描述:Welcome to VNCTF 2024~ long time no see. 开题,是前端小游戏 源码里面发现一个16进制编码字符串 解码后是flag CutePath 题目描述:源自一次现实渗透 开题 当前页面没啥好看的,先爆破密码登录试试。爆破无果…...

第11章 GUI
11.1 Swing概述 Swing是Java语言开发图形化界面的一个工具包。它以抽象窗口工具包(AWT)为基础,使跨平台应用程序可以使用可插拔的外观风格。Swing拥有丰富的库和组件,使用非常灵活,开发人员只用很少的代码就可以创建出…...

综合项目---博客
一.运行环境 192.168.32.132 Server-Web linux Web 192.168.32.133 Server-NFS-DNS linux NFS/DNS 基础配置 1.配置主机名静态ip 2.开启防火墙并配置 3.部分开启selinux并配置 4.服务器之间通过阿里云进行时间同步 5.服务器之间实现ssh免密…...

leetcode(矩阵)74. 搜索二维矩阵(C++详细解释)DAY7
文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中…...

超详细||YOLOv8基础教程(环境搭建,训练,测试,部署看一篇就够)(在推理视频中添加FPS信息)
一、YOLOv8环境搭建 这篇文章将跳过基础的深度学习环境的搭建,如果没有完成的可以看我的这篇博客:超详细||深度学习环境搭建记录cudaanacondapytorchpycharm-CSDN博客 1. 在github上下载源码: GitHub - ultralytics/ultralytics: NEW - YO…...

LeetCode171. Excel Sheet Column Number
文章目录 一、题目二、题解 一、题目 Given a string columnTitle that represents the column title as appears in an Excel sheet, return its corresponding column number. For example: A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … Exa…...

pycharm创建py文件,自动带# -*- coding:utf-8 -*-
File–Settings...

希捷与索尼集团合作生产HAMR写头激光二极管
最近有报道指出,希捷(Seagate)在生产其采用热辅助磁记录(HAMR)技术的大容量硬盘时,并非所有组件都在内部制造。根据日经新闻的一份新报告,希捷已与索尼集团合作,由索尼为其HAMR写头生…...

电脑竖屏显示了怎么回复原状
电脑屏幕变成这样 怎么恢复原状? 1、登录系统 2、在桌面上空白点击鼠标右键 3、在右键菜单中选择“屏幕分辨率”,左键点击打开 4、在窗口中“方向”位置选择“横向” 5、保存设置win7桌面即可恢复到正常状态...

Elasticsearch从入门到精通
目录 🧂1.简单介绍 🥓2.安装与下载 🌭3.安装启动es 🍿4.安装启动kibana 🥞5.初步检索 🧈6.进阶检索 🫓7.Elasticsearch整合 1.简单介绍🚗🚗🚗 Elat…...

Halcon 相机标定
文章目录 算子单相机标定单相机标定畸变的矫正 算子 gen_caltab 生成标定文件 gen_caltab(::XNum,YNum,MarkDist,DiameterRatio,CalTabDescrFile,CalTabPSFile :) 算子来制作一个标定板XNum 每行黑色标志圆点的数量。YNum 每列黑色标志圆点的数…...