【计算机网络】日志与守护进程

news2024/12/27 0:35:55

文章目录

  • 日志
    • 日志的创建
      • 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_t
   struct 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,//2
  BIND_ERR,//3
  LISTEN_ERR,//4
  SETSID_ERR,//5
  OPEN_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,//2
  BIND_ERR,//3
  LISTEN_ERR,//4
  SETSID_ERR,//5
  OPEN_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);

  } 


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

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

相关文章

centos7.6安装、卸载openssh

1.卸载openssh 执行 rpm -qa openssh*查看是否已经安装过了。 rpm -qa openssh* 依次卸载&#xff1a; yum remove openssh-server-7.4p1-23.el7_9.x86_64 yum remove openssh-7.4p1-23.el7_9.x86_64 或者使用&#xff1a;yum remove openssh-* 全部卸载掉 yum remove opens…

客户案例:中圣科技—CAC2.0防范盗号威胁,加固安全防线

客户背景 中圣科技&#xff08;江苏&#xff09;股份有限公司&#xff08;以下简称“中圣科技”&#xff09;&#xff0c;是一家以技术研发为驱动&#xff0c;以清洁能源核心成套装备和节能环保工程服务为支撑的科技创新型企业。其以南京为核心运营基地&#xff0c;与当地政府…

【云原生】3分钟快速在Kubernetes1.25部署Prometheus2.42+Grafana9.5.1+Alertmanager0.25

文章目录 1、简介2、GitHub地址3、环境信息4、安装5、访问Grafana1、简介 Prometheus-operator帮助我们快速创建Prometheus+Grafana+Alertmanager等服务,而kube-prometheus更加完整的帮助我们搭建全套监控体系,这包括部署多个 Prometheus 和 Alertmanager 实例, 指标导出器…

Ubuntu20 安装 libreoffice

1 更新apt-get sudo apt-get update2 安装jdk 查看jdk安装情况 Command java not found, but can be installed with:sudo apt install default-jre # version 2:1.11-72, or sudo apt install openjdk-11-jre-headless # version 11.0.138-0ubuntu1~20.04 sud…

发布 net 项目 到 Docker

背景 因为发布到 centOS8 使用 screen -S 可以&#xff0c;想开机自启 使用 nohup 命令有启动不起来。环境问题不好找&#xff0c;就想尝试用 docker 运行 步骤 在生成的 Dockerfile 文件里增加修改时区指令 因为我们用的都是北京时间所以 创建镜像的时候就调整好 #设置时间…

SQLSTATE[IMSSP]: The active result for the query contains no fields.

我的是SQL server 报错场景&#xff0c;代码&#xff1a; $psendmx_sql"SET IDENTITY_INSERT PSENDMX ON;INSERT INTO psendmx (DJBH,MIBH,MXBH,SPDM,GG1DM,GG2DM,SL,SL_2,CKJ,ZK,DJ,DJ_1,JE,HH) VALUES {$mx_values};SET IDENTITY_INSERT PSENDMX OFF;"; $a$db_er…

算法通关村第九关——透彻理解二分查找

1.前言 常见的查找算法有顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找、哈希查找等。如果进行归类&#xff0c;那么二分查找、插值查找&#xff08;一种查找算法&#xff09;以及斐波那契查找都可以归为插值查找&#xff08;大类&#xff09;。而插值查找…

macOS上编译obs-studio

前言 最近基于obs的1个二开程序&#xff0c;需要移植到macOS平台上&#xff0c;由于遇到些问题&#xff0c;本文记录下如何在macOS上配置&编译&运行obs程序完整过程。 下载 首先下载cmake-gui工具&#xff0c;下载CMAKE&#xff0c;选择对应macOS平台的cmake版本&…

过来人经验,PMP考试第七版要怎么学?

第七版没有大家说的那么难&#xff0c;根据考纲来看&#xff0c;一半内容将考查预测型项目管理方法&#xff0c;一半考查敏捷或混合型方法 &#x1f308;备考建议是&#xff1a;先学第六版和敏捷&#xff0c;再来学第七版&#xff0c;第七版其实可以理解为第六版的升级&#xf…

java八股文面试[JVM]——垃圾回收

参考&#xff1a;JVM学习笔记&#xff08;一&#xff09;_卷心菜不卷Iris的博客-CSDN博客 GC垃圾回收面试题&#xff1a; JVM内存模型以及分区&#xff0c;需要详细到每个区放什么 堆里面的分区&#xff1a;Eden&#xff0c;survival from to&#xff0c;老年代&#xff0c;各…

7-模板过滤器

一. 过滤器 过滤器: 过滤器本质就是函数 # 模板语法中过滤器: {{ 变量名| 过滤器 }} {{ 变量名| 过滤器(*args) }}二. 常见的过滤器 str 过滤器的相关操作: safe :禁用转义 capitalize: 单词的首字母大写 lower 和 upper: 大小转换 title : 一句话中的每个单词的首字母大写 r…

机器学习深度学习——NLP实战(自然语言推断——注意力机制实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——NLP实战&#xff08;自然语言推断——数据集&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习&…

科脉收银系统中了360勒索病毒怎么办?勒索病毒解密,数据恢复

在商超、大卖场、连锁便利店和餐饮店的收银系统当中&#xff0c;科脉绝对是一个不得不提的产品。正因为其在市场当中有着极高的占有率&#xff0c;才使得其成为了勒索病毒攻击的主要目标之一。近几日&#xff0c;云天数据恢复中心就接到好多客户的咨询&#xff0c;在这些客户当…

视频云存储/安防监控EasyCVR视频汇聚平台接入GB国标设备时,无法显示通道信息该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

SpringBoot整合Quartz,实现数据库方式执行定时任务

springboot整合quartz&#xff0c;实现数据库方式执行定时任务。把定时任务信息存进数据库&#xff0c;项目启动后自动执行定时任务。 1.引入依赖包&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <ar…

牛客刷题第二弹

ASCII 定义在类中的变量是类的成员变量&#xff0c;可以不进行初始化&#xff0c;Java会自动进行初始化&#xff0c;如果是引用类型默认初始化为null,如果是基本类型例如int则会默认初始化为0 局部变量是定义在方法中的变量&#xff0c;必须要进行初始化&#xff0c;否则不同…

论文阅读及复现——《CT_ICP: Real-time Elastic LiDAR Odometry with Loop Closure》

论文阅读之——《CT_ICP: Real-time Elastic LiDAR Odometry with Loop Closure》带闭环的实时弹性激光雷达里程计 1. 主要贡献2. 相关说明3. 激光里程计3.1 里程计公式构建3.2 局部地图与健壮性 4. 回环检测与后端5. 实验结果5.1 里程计实验结果5.2 回环检测实验结果 6. 总结…

构造函数内的方法 直接写在构造函数内部 与 写在prototype上 的区别

文章目录 前言区别总结 前言 以前没注意过, 去创建一个构造函数的时候, 方法都是直接写在函数内的. 在构造函数需要多次实例化的情况下有缺点, 不过幸好以前项目里的构造函数也不需要多次实例化, 缺点没有生效. 区别 为了比较, 先在构造函数内部直接书写方法, 查看实例化结果…

问题来了!你知道你穿的防砸劳保鞋的保护包头都是什么材料

防砸劳保鞋是较为常见的一种劳保鞋&#xff0c;用于作业过程中保护工人的脚&#xff0c;减少或避免被坠落物、重物砸伤或压伤脚部的工作鞋。防砸安全鞋鞋前头装有防护包头&#xff0c;具有耐压力和抗冲击性能。主要适用于矿山、机械、建筑、钢铁、冶金、运输等行业。 你穿的防砸…

NLog 使用

环境 .net 6.0 控制台程序 第三方库 NLog.Extensions.Logging Microsoft.Extensions.DependencyInjection 创建 NLog 配置文件 记得设置始终赋值&#xff0c;生成到发布文件夹 <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"h…