【计算机网络】日志与守护进程
文章目录
- 日志
- 日志的创建
- logmessage 函数
- 日志左边部分实现
- 日志右边部分实现
- 完整代码
- log.hpp(整体实现)
- err.hpp (错误信息枚举)
- 守护进程
- PGID SID TTY 的介绍
- shell中控制进程组的方式
- 结论
- 为什么要有守护进程存在?
- 守护进程的创建
- 使用守护进程的条件
- 守护进程化的函数
- 自己实现守护进程化
- 解决组长问题
- 忽略信号
- 处理 0 1 2 问题
- 退出守护进程
- 完整代码
- err.hpp(错误信息枚举)
- daemon.hpp(整体实现)
日志
一般使用cout进行打印,但是cout打印是不规范的
实际上 是采用日志进行打印的
日志的创建
创建一个 log.hpp
日志有自己的日志等级
通过枚举,分别为 调试 常规 告警 一般错误 致命错误 未知错误
logmessage 函数
定义一个函数 logmessage,参数level 为日志等级 ,
为了按照可变参数的方式,来进行格式化输出,所以设置一个format 以及…可变参数(可以给c函数传递任意个数的参数)
日志左边部分实现
输入 man snprintf
将可变参数的内容显示到str字符串中
获取日志等级
设置一个字符串 level_string ,通过tolevelstring函数 将数字转化为字符串
获取时间
输入 man localtime
将time_t转换为 struct tm 结构体类型
该结构体包含 秒 分 时 天
输入 man 3 time

通过gettime函数 获取时间
日志右边部分实现
为了处理可变参数部分,所以使用vsprintf
输入 man snprintf
将写好的数据放到logRight中
完整代码
log.hpp(整体实现)
#pragma once
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cstring>
#include<cstdarg>
#include<unistd.h>
#include<sys/types.h>
#include<time.h>const std::string filename="tecpserver.log";//日志等级
enum{DEBUG=0, // 用于调试INFO , //1 常规WARNING, //2 告警ERROR , //3 一般错误FATAL , //4 致命错误UKNOWN//未知错误
};static std::string tolevelstring(int level)//将数字转化为字符串
{switch(level){case DEBUG : return "DEBUG";case INFO : return "INFO";case WARNING : return "WARNING";case ERROR : return "ERROR";case FATAL : return "TATAL";default: return "UKNOWN";}
}
std::string gettime()//获取时间
{time_t curr=time(nullptr);//获取time_tstruct tm *tmp=localtime(&curr);//将time_t 转换为 struct tm结构体char buffer[128];snprintf(buffer,sizeof(buffer),"%d-%d-%d %d:%d:%d",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday,tmp->tm_hour,tmp->tm_min,tmp->tm_sec);return buffer;}
void logmessage(int level, const char*format,...)
{//日志左边部分的实现char logLeft[1024];std::string level_string=tolevelstring(level);std::string curr_time=gettime();snprintf(logLeft,sizeof(logLeft),"%s %s %d",level_string.c_str(),curr_time.c_str());//日志右边部分的实现char logRight[1024]; va_list p;//p可以看作是1字节的指针va_start(p,format);//将p指向最开始vsnprintf(logRight,sizeof(logRight),format,p);va_end(p);//将指针置空//打印日志 printf("%s%s\n",logLeft,logRight);//保存到文件中FILE*fp=fopen( filename.c_str(),"a");//以追加的方式 将filename文件打开//fopen打开失败 返回空指针if(fp==nullptr){return;}fprintf(fp,"%s%s\n",logLeft,logRight);//将对应的信息格式化到流中fflush(fp);//刷新缓冲区fclose(fp);
}
err.hpp (错误信息枚举)
#pragma once enum
{USAGE_ERR=1,SOCKET_ERR,//2BIND_ERR,//3LISTEN_ERR,//4SETSID_ERR,//5OPEN_ERR//6
};
守护进程
网络服务一定在任何时候都能访问,所以这个服务不能受任何用户的登录或者注销各种行为的影响
所以需要将进程进行守护进程化
PGID SID TTY 的介绍
在后台运行sleep 10000
PPID是bash的PID值
PGID是 进程组 (PGID相同就为同一个进程组,以从第一个进程进行命名)
SID 是 会话ID
TTY是 终端 若为?,则说明跟终端没有关系,若为具体的如pts/5,则为终端文件
在终端2中输入,在终端1中可以查看到 两者的PGID相同,所以属于同一个进程组,并且以sleep 1000 作为组长
通过查询会话ID 21668,发现bash的PID PGUD SID 都为21668
shell中控制进程组的方式
查询后台任务 jobs
当再次输入sleep 5000 进行后台运行时,发现前面的编号变成2
该编号为 任务编号
将某一任务提到前台运行 fg + 任务编号
当把1号任务提到前台后,再次使用jobs查询后台任务,就查不到1号任务了
并且其他任务并不受影响
把2号任务提到前台,使用 ctrl z 让服务暂停起来
在暂停后,任务会自动切换到后台
输入 bg 2,让2号任务在后台跑起来
结论
1. 进程组分为 前台任务 和 后台任务
在终端2中创建后台任务和前台任务,在终端1中查询发现,后台任务的(PGID)进程组 和 (SID)会话ID相同 ,而与后台的不同
2. 如果后台任务提到前台,老的前天任务就无法运行
将任务编号为1的后台任务 使用 fg 提到前台后 ,输入 ls pwd 等 指令是没有作用的
会话中 ,只能有一个前台任务在运行
所以当 使用 ctrl c 将1号任务退出后,bash把自己变成了前台任务,所以又可以运行了
为什么要有守护进程存在?
若登录就是创建一个会话,启动进程,会话内部有bash任务,在当前会话中创建新的前后台任务,那如果退出呢?
当退出时,就会销毁会话可能会影响会话内部的所有任务
网络服务器为了不受到用户登录注销的影响,网络服务器 通常以守护进程的方式运行
守护进程的创建
输入 man 2 setsid
设置一个会话,以进程组的组长ID作为新的会话ID
若返回成功,则返回调用进程的PID,若返回失败,则返回-1并设置错误码
想要调用setsid,不可以是组长
如:在一家公司中你是组长,有一天你想不干了 出去创业 是不可以的,因为你手底下有一堆组员
所以要成功出去创业,就必须卸任你的组长身份
使用守护进程的条件
1.忽略异常
2.对 0(标准输入) 1(标准输出) 2(标准错误) 作特殊处理
3.进程的工作路径 可能要更改
4.守护进程是一个全局的进程,不想在某一个用户的目录下,所以从整个系统中从最开始进行索引某些文件
守护进程化的函数
输入 man daemon,提供守护进程化的函数
第一个参数表示 是否更改 工作目录,默认不要改,改为1表示为真
第二个参数表示 要不要关闭 0 1 2, 默认不关
大部分情况下,都是自己实现守护进程,而不是调用该函数
自己实现守护进程化
解决组长问题
当启动时,是在bash中新起一个任务,只有一个进程自成进程组,所以自成组长,操作不被允许
成为组长的一般都是组中的第一个进程,所以只需使其不为第一个进程即可
输入 man fork,创建子进程
fork的返回值:父进程返回子进程的PID值,子进程返回0,失败返回-1
当fork>0时,说明为父进程,则让父进程退出,只剩下子进程,子进程不是进程的第一个,也就不是组长,就可以成功调用setsid
忽略信号
signal的第一个参数 表示 信号 ,第二个参数表示对指定动作的信号设定自定义处理动作
SIGPIPE 表示13号信号
SIG_IGN 为 自定义处理信号处理函数
把1强制转化成函数指针类型 即忽略信号
对13号信号 进行忽略
SIGCHLD信号
子进程在运行时会退出,若父进程不关心子进程退出,子进程就会变成僵尸状态
父进程要使用 wait/waitpid去等待子进程 回收僵尸,获取子进程的退出结果
即父进程进行阻塞式等待(什么都不干,就等待子进程的退出结果)
子进程要退出时,会向父进程发信号 SIGCHLD
所以同样对 SIGCHLD信号 进行忽略
处理 0 1 2 问题
使用日志打印,所以导致有很多输出结果,但输出结果不想往显示器上面打印,所以就需要处理标准输入 标准输出 标准错误
Linux系统提供一个 dev null的字符设备
向dev null 中写入,都会被丢弃 ,从这个文件读什么都读不到 ,立马直接返回
输入 man 2 open,打开文件
若返回成功,则返回 文件描述符,若返回失败,则返回 -1 并将错误码返回
O_RDWR : 读写的方式
重定向函数 :输入 man dup2
可以直接将文件打开,使用dup2重定向
输出重定向对应的文件描述符是1
假设其文件描述符是fd
newfd为oldfd的一份拷贝,最后只剩下oldfd
dup2(fd,1) 即 将标准输出流 重定向到 文件描述符fd中
退出守护进程
输入 kill -9 + 守护进程的PID,即可退出守护进程
完整代码
err.hpp(错误信息枚举)
#pragma once enum
{USAGE_ERR=1,SOCKET_ERR,//2BIND_ERR,//3LISTEN_ERR,//4SETSID_ERR,//5OPEN_ERR//6
};
daemon.hpp(整体实现)
#pragma once
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include"log.hpp"
#include"err.hpp"void Daemon()//自己实现服务器的守护进程化{//1.忽略信号signal(SIGPIPE,SIG_IGN);//忽略信号signal(SIGCHLD,SIG_IGN);//2.不要成为组长 if(fork()>0)//说明为父进程,则让父进程直接退出{exit(0);}//只剩下子进程//3.新建会话,自己成为会话的话首进程pid_t ret=setsid();if((int)ret==-1)//守护进程失败{logmessage(FATAL,"deamon error,code:%d,string :%s",errno,strerror(errno));exit(SETSID_ERR);//终止程序}//4.可以更改守护进程的工作路径//5.处理 0 1 2 问题int fd=open("/dev/null",O_RDWR);//以读写的方式打开字符设备if(fd<0){logmessage(FATAL,"deamon error,code:%d,string :%s",errno,strerror(errno));exit(OPEN_ERR);//终止程序} //将标准输入 输出错误 重定向到字符设备中dup2(fd,0);dup2(fd,1);dup2(fd,2);close(fd);} 相关文章:
【计算机网络】日志与守护进程
文章目录 日志日志的创建logmessage 函数日志左边部分实现日志右边部分实现 完整代码log.hpp(整体实现)err.hpp (错误信息枚举) 守护进程PGID SID TTY 的介绍shell中控制进程组的方式结论 为什么要有守护进程存在?守护进程的创建使用守护进程的条件守护进…...
设计模式之职责链模式(ChainOfResponsibility)的C++实现
1、职责链模式的提出 在软件开发过程中,发送者经常发送一个数据请求给特定的接收者对象,让其对请求数据进行处理(一个数据请求只能有一个对象对其处理)。如果发送的每个数据请求指定特定的接收者, 将带来发送者与接收…...
CGAL Mesh(网格数据)布尔操作
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Mesh布尔操作是一种在三维计算机图形学中用于组合两个或多个网格(mesh)对象的方法。它可以将两个网格对象组合成一个新的对象,同时保留原始对象的拓扑结构和几何信息。Mesh布尔操作主要有以下三种类型: Union(…...
技术分享| WebRTC之SDP详解
一,什么是SDP WebRTC 是 Web Real-Time Communication,即网页实时通信的缩写,是 RTC 协议的一种Web实现,项目由 Google 开源,并和 IETF 和 W3C 制定了行业标准。 WebRTC是点对点通讯,他的通话建立需要交换…...
Flink Table API/SQL 多分支sink
背景 在某个场景中,需要从Kafka中获取数据,经过转换处理后,需要同时sink到多个输出源中(kafka、mysql、hologres)等。两次调用execute, 阿里云Flink vvr引擎报错: public static void main(String[] args) {final StreamExecuti…...
Vue3 中 导航守卫 的使用
在Vue 3中,导航守卫(Navigation Guards)用于在路由切换前后执行一些操作,例如验证用户权限、取消路由导航等。Vue 3中的导航守卫与Vue 2中的导航守卫略有不同。下面是Vue 3中导航守卫的使用方式: 全局前置守卫…...
云原生概论
云原生是一种新兴的技术趋势,它旨在将应用程序设计和部署方式从传统的基础设施转向云端。云原生应用程序是一种针对云环境进行优化的应用程序,能够充分利用云端提供的弹性和可扩展性。本文将探讨云原生的概念、优势、应用场景以及未来发展方向。 一、云…...
hive-sql
hive-常用SQL汇总 查看数据库 -- 查看所有的数据库 show databases; 使用默认的库 -- 下面的语句可以查看默认的库 use default ;查看某个库下的表 -- 查看所有的表 show tables ; -- 查看包含 stu的表 ,这种是通配的方法来查看 show tables like *stu*; 查…...
Rspack 创建 vue2/3 项目接入 antdv(rspack.config.js 配置 less 主题)
一、简介 Rspack CLI 官方文档。 rspack.config.js 官方文档。 二、创建 vue 项目 创建项目(文档中还提供了 Rspack 内置 monorepo 框架 Nx 的创建方式,根据需求进行选择) # npm 方式 $ npm create rspacklatest# yarn 方式 $ yarn create…...
基于centos7完成docker服务的一些基础操作
目录 要求完成 具体操作 1.安装docker服务,配置镜像加速器 2.下载系统镜像(Ubuntu、 centos) 3.基于下载的镜像创建两个容器 (容器名一个为自己名字全拼,一个为首名字字母) 4.容器的启动、 停止及重启…...
Microsoft Visual Studio + Qt插件编程出现错误error MSB4184问题
文章目录 报错解决 报错 C:\Users\Administrator\AppData\Local\QtMsBuild\qt_globals.targets(786,7): error MSB4184: 无法计算表达式“[System.IO.File]::ReadAllText(C:\Users\Administrator\AppData\Local\QtMsBuild\qt.natvis.xml)”。 未能找到文件“C:\Users\Administ…...
QT Quick之quick与C++混合编程
Qt quick能够生成非常绚丽界面,但有其局限性的,对于一些业务逻辑和复杂算法,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可…...
Ros noetic Move_base 相关状态位置的获取 实战使用教程
前言: 有一段时间没有更新,这篇文章是为了后续MPC路径跟踪算法开设的帖子用于更新我自己的思路,由于MPC算法,要镶嵌到整个导航任务中去,就绕不开这个move_base包中相关的参数设置和其中相关状态位置的获取和解读等等。 因为最近遇到小车在其他的环境中有些时候,不需要自己…...
【SpringBoot】SpringBoot项目与Vue对接接口的步骤
下面是SpringBoot项目与Vue对接接口的步骤: 创建SpringBoot项目,在项目中添加依赖,如Spring MVC、MyBatis等框架。 在SpringBoot项目中编写接口方法,使用注解标识请求方式,如GetMapping、PostMapping等,并…...
Glog安装与使用
安装 脚本 #!/bin/bash git clone https://github.com/google/glog.git cd glog git checkout v0.4.0 mkdir build && cd build cmake .. make -j4 echo "your password" | sudo -S make install使用 main.cc #include <glog/logging.h>int main(i…...
windows开发环境搭建
下载msys2,官网下载即可: MSYS2 安装其他的编译工具(貌似不需要把中间的命令全部执行): MSYS2使用教程——win10系统64位安装msys2最新版(msys2-x86_xxxx.exe)_msys64_Dreamhai的博客-CSDN博…...
8月17日上课内容 第三章 LVS+Keepalived群集
本章结构 Keepalived概述 keepalived 概述 1.服务功能 故障自动切换 健康检查 节点服务器高可用 HA keepalived工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题 在一个LVS服务集群中通常有主服务器 (MAST…...
Threejs学习05——球缓冲几何体背景贴图和环境贴图
实现随机多个三角形随机位置随机颜色展示效果 这是一个非常简单基础的threejs的学习应用!本节主要学习的是球面缓冲几何体的贴图部分,这里有环境贴图以及背景贴图,这样可以有一种身临其境的效果!这里环境贴图用的是一个.hdr的文件…...
LVS+Keepalived群集实验
目录 Keepalived 是什么 Keepalived 功能 Keepalived 模块 工作原理 脑裂现象及解决方案 脑裂 形成脑裂的原因 解决脑裂的几种方法: 为了减少或避免HA集群中出现脑裂现象,我们可以采取以下措施: Keepalived服务主要功能࿰…...
软考高级之系统架构师之系统开发基础
架构 场景 场景(scenarios)在进行体系结构评估时,一般首先要精确地得出具体的质量目标,并以之作为判定该体系结构优劣的标准。为得出这些目标而采用的机制做场景。场景是从风险承担者的角度对与系统的交互的简短描述。在体系结构…...
Gemini自动生成PPT实战手册:从零输入到专业演示文稿,3步完成95%的幻灯片工作流
更多请点击: https://intelliparadigm.com 第一章:Gemini自动生成PPT的核心原理与能力边界 Gemini 生成 PPT 的本质并非传统模板填充,而是基于多模态理解与结构化内容重构的端到端推理过程。其核心依赖于对用户输入(文本、大纲、…...
告别驱动开发:手把手教你用himm工具在用户空间玩转Hi3516的GPIO
用户空间高效操控Hi3516 GPIO:himm工具实战指南 在嵌入式开发领域,传统的内核驱动开发往往需要经历漫长的编译、加载和调试周期。对于快速硬件验证和原型开发而言,这种开发模式显得过于笨重。海思Hi3516平台提供的himm工具,为开发…...
绩效考核的量化迷思:如何衡量不可直接测量的技术贡献
一、量化绩效考核的困境:软件测试的“隐形”价值在软件行业的绩效考核体系中,量化指标似乎成了“公平”与“高效”的代名词。代码行数、Bug数量、测试用例覆盖率……这些清晰可统计的数字,被当作衡量技术人员贡献的核心标尺。然而,…...
VCF 9.1 新特性:安装器与 Fleet Depot 支持 HTTP 无认证离线软件源
VMware Cloud Foundation(VCF)9.0 推出了统一软件仓库(Software Depot),支持连接博通在线源或企业内部离线源。但在 9.0 中,离线源默认必须使用 HTTPS 基础认证,即使关闭 HTTPS 也依然需要认证,对纯内网环境很不友好。在 VCF 9.1…...
从‘能用’到‘优雅’:Python函数设计的3个坏味道与5个重构技巧(附代码对比)
从‘能用’到‘优雅’:Python函数设计的3个坏味道与5个重构技巧(附代码对比) 在Python开发中,函数是最基本的代码组织单元。许多开发者能够快速实现功能,却往往忽视了函数设计的质量。本文将揭示三种典型的函数设计&qu…...
信息学奥赛刷题实战:用C++搞定OpenJudge NOI 1.4 09题(判断整除)的四种思路
信息学奥赛刷题实战:用C搞定OpenJudge NOI 1.4 09题(判断整除)的四种思路 在信息学奥赛(NOI)和OpenJudge等编程竞赛平台上,一道看似简单的题目往往隐藏着多种解题思路。今天,我们就以OpenJudge …...
用PyTorch复现DKT模型:从Assistment数据集处理到LSTM训练全流程(附完整代码)
用PyTorch构建DKT模型:从数据预处理到LSTM实战全解析 在教育技术领域,追踪学生知识掌握程度一直是个核心挑战。想象一下,当学生在在线学习平台上完成一系列数学题时,系统如何预测他们下一步可能遇到的困难?这正是深度知…...
Hive内部表 vs 外部表:选错一次,数据全丢?结合HDFS路径详解核心区别与选型指南
Hive内部表与外部表:数据安全与架构设计的深度抉择 在数据仓库与大数据分析领域,Hive作为构建在Hadoop之上的数据仓库工具,其表类型的选择往往被初学者视为简单的语法差异。然而,当生产环境中TB级的数据因为一个DROP TABLE命令而永…...
从理论到实践:径向基函数(RBF)插值在数据拟合中的应用
1. 径向基函数插值:给离散数据穿上连续外衣 第一次接触RBF插值时,我正在处理一组气象站采集的温度数据。这些站点像随意撒在地图上的芝麻,有的区域密集,有的区域稀疏。当我试图绘制全国温度分布图时,传统线性插值产生的…...
从Java后端到AI风口:转型踩坑一年,我悟了!涨薪30%的真相是…
做了八年Java后端,去年咬牙转型AI应用开发。这一年踩过坑、加过班、也被面试官问倒过。但回头看,这条路选对了——薪资涨了30%,职业空间也打开了。我必须告诉那些还在犹豫要不要从后端跳出来的同行——现在的AI应用开发社招,确实是…...
