当前位置: 首页 > news >正文

日志和守护进程

 日志

//日志就是服务器在运行的时候要定期的把执行痕迹保留下来
#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>// 日志是有日志等级的,有的报错无关紧要,有的日志可以反应很严重的错误const std::string filename = "log/tcpserv er.log";//日志位于当前目录下的log文件夹内部enum
{Debug = 0,//用于调试Info,//常规等级,正常显示Warning,//告警,并不是错误Error,//一般错误,不影响继续向后运行Fatal,//致命的错误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";//这种出错一般不会影响代码的后续运行,比如read的返回值小于0case Fatal:return "Fatal";//这种错误发生一般会直接exit或者return,比如说创建套接字失败。default:return "Uknown";}
}static std::string getTime()
{time_t curr = time(nullptr);//拿到当前的时间struct tm *tmp = localtime(&curr);//将time_t类型转换成为一个结构体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);//tm结构体中关于年的成员是减去了1900的return buffer;
}// 日志格式: 日志等级 时间 pid 消息体
// logMessage(DEBUG, "hello: %d, %s", 12, s.c_str()); // DEBUG hello:12, world
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(), getpid());//int snprintf(char *str, size_t size, const char *format, ...);将对应的格式信息写入到logleft当中。//消息体char logRight[1024];va_list p;va_start(p, format);//让p指向可变参数的起始部分vsnprintf(logRight, sizeof(logRight), format, p);//这里不采用遍历字符串找%d、%f来进行分析,也就是va_arg的方式,int vsnprintf(char *str, size_t size, const char *format, va_list ap);va_end(p);// 打印// printf("%s%s\n", logLeft, logRight);// 将日志保存到文件中,因为当该进程变成守护进程的时候,这些信息无法打印到显示器上了。FILE *fp = fopen(filename.c_str(), "a");if(fp == nullptr)return;fprintf(fp,"%s%s\n", logLeft, logRight);fflush(fp); //刷新,可写也可以不写,因为fclose也会刷新。fclose(fp);// 预备//  va_list p; // char *类型,也就是定义一个指针//  int a = va_arg(p, int);  // 根据类型提取参数,我如何知道类型的呢,那就是根据format当中的%d、%p,这些就是我们所说的数据类型。//  va_start(p, format); //p指向可变参数部分的起始地址,可变参数一定和前一个参数format是挨着的,相当于对format取地址然后进行偏移从而取到可变参数的起始地址//  va_end(p); // p = NULL;//我们可以通过上面的一个变量和三个宏函数来提取可变参数的各个部分
}

守护进程

PGID是进程组,SID是会话id,TTY指的是终端文件,?指的是对应进程和终端没有关系,而pts/3指的是终端文件,说明sleep 10000这个进程和该终端文件时关联的,也就是该进程打开了这个终端。所以我们在执行ls、pwd的时候,会有对应的信息打印在该终端设备上,原因是因为进程运行时把该终端文件打开了,然后把对应的内容朝该终端文件中进行了写入。

会话>=进程组>=进程,固定的会话会关联一个固定的终端文件,进程组长就是多个进程当中的第一个,而会话进程也是一个bash进程。

如果我们用xshell再次登录我们的Linux系统,本质上我们的Linux要帮我们创建另外一个会话,未来在新的终端执行命令时,也是在这个会话里面运行的。

jobs查看该会话内部的所有任务,fg可以将任务切换到前台,前台任务进行ctrl + z将可以暂停该任务,然后bg就可以让任务继续在后台运行。这就是shell中控制进程组的方式。

1、进程组分为前台任务和后台任务

2、如果后台任务提到前台,也就是谁当前使用该终端,老的前台任务bash就无法运行了。ctrl+c可以干掉该任务然后让bash重新回到前台运行

3、任何时刻,在会话中只能有一个前台任务在运行!所以我们在命令行启动一个前台进程之后,bash就无法运行了。

4、如果登录就是创建一个会话,bash任务,启动我们的进程,就是在当前会话中创建新的前后台任务,那么如果我们退出呢就是销毁该会话,销毁会话就可能会影响会话内部的所有任务。

一般网络服务器,为了不受到用户登注销的影响,就需要让该进程该会话中独立出来,不要跟任何一个用户会话产生关联,独立成为一个会话,从包含关系变成并列关系,就有了守护进程的运行方式。   pid_t setsid(void)谁调用该函数就把自己设立成为一个新的会话,成功了就返回调用进程的pid。 

为什么要有进程组呢?进程组是用来完成任务的,而任务 

#pragma once
// .\xxx是在前台运行,而.\xxx &是在后台运行
// 1. setsid();
// 2. setsid(), 调用进程,不能是组长!我们怎么保证自己不是组长呢?
// 3. 守护进程a. 忽略异常信号 b. 对于标准输入0,标准输出1,标准错误2要做特殊处理 c. 进程的工作路径可能要更改 /,也就是守护进程是一个全局进程,不想在某个用户文件夹下#include <cstdlib>
#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)//fork大于0就是父进程。于是直接退出就可以了。所以守护进程的本质:是孤儿进程的一种!exit(0);// 3. 新建会话,自己 成为会话的话首进程pid_t ret = setsid();//子进程执行setsid的时候,就不是进程组的第一个了。if ((int)ret == -1){logMessage(Fatal, "deamon error, code: %d, string: %s", errno, strerror(errno));exit(SETSID_ERR);}// 4. 可选:可以更改守护进程的工作路径// chdir("/")// 5. 处理后续的对于0,1,2的问题。已经守护进程化了,不想还往显示器进行打印,简单粗暴的做法就是直接close掉,万一代码里面有cin、cout就会直接报错。int fd = open("/dev/null", O_RDWR);if (fd < 0){logMessage(Fatal, "open error, code: %d, string: %s", errno, strerror(errno));exit(OPEN_ERR);}dup2(fd, 0);//把0、1、2重定向到这个信息黑洞当中,直接丢弃掉。dup2(fd, 1);dup2(fd, 2);close(fd);
}

/dev/null是一个字符设备,往其打印内容或者是从其获取内容都是没有任何反应的。 守护进程一启动不会阻塞在前台,而且把自己单独拎出去了,和当前会话就没有关系了。我们通过jobs在该会话中是看不到的,并且通过ps ajx查看该进程会发现它的TTY会变成?,并且自称进程组、自称会话。现在将xshell关闭,该进程仍然可以运行,因为它是守护进程。现在jobs是看不到了,因为他已经独立会话了,不属于我这个会话了。想要关闭该进程需要通过kill。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 人大金仓(Kingbase)数据库高阶函数详解
  • Java中的网络协议实现:HTTP/2与gRPC
  • 计算机的错误计算(五十四)
  • SpringBoot依赖之Quartz Scheduler定时调度器
  • Vue 3+Vite+Eectron从入门到实战系列之(三)一Electron热身运动(一)
  • 智慧公厕系统解决方案实现更人性化的服务
  • 基于深度学习的数据并行与模型并行
  • Java | Leetcode Java题解之第327题区间和的个数
  • Harmony OS 用户通知服务
  • 第三章 LVS+Keepalived群集
  • C++转Java基础知识
  • Python学习笔记50:游戏篇之外星人入侵(十一)
  • RUM技术探索:前端监控数据采集与实践
  • CRITIC权重法
  • c++STL中list介绍,模拟实现和list与vector对比
  • 【React系列】如何构建React应用程序
  • Codepen 每日精选(2018-3-25)
  • ECMAScript6(0):ES6简明参考手册
  • Java反射-动态类加载和重新加载
  • leetcode386. Lexicographical Numbers
  • LeetCode算法系列_0891_子序列宽度之和
  • OSS Web直传 (文件图片)
  • Sequelize 中文文档 v4 - Getting started - 入门
  • Vue.js源码(2):初探List Rendering
  • Web设计流程优化:网页效果图设计新思路
  • 山寨一个 Promise
  • 项目实战-Api的解决方案
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (全注解开发)学习Spring-MVC的第三天
  • (新)网络工程师考点串讲与真题详解
  • (转)VC++中ondraw在什么时候调用的
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .NET C# 使用 iText 生成PDF
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net 高效开发之不可错过的实用工具
  • .Net--CLS,CTS,CLI,BCL,FCL
  • .Net各种迷惑命名解释
  • .ui文件相关
  • //解决validator验证插件多个name相同只验证第一的问题
  • ??Nginx实现会话保持_Nginx会话保持与Redis的结合_Nginx实现四层负载均衡
  • @Service注解让spring找到你的Service bean
  • [000-01-022].第06节:RabbitMQ中的交换机介绍
  • [20150904]exp slow.txt
  • [2669]2-2 Time类的定义
  • [8481302]博弈论 斯坦福game theory stanford week 1
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标
  • [C++进阶]map和set的相关题目
  • [CTO札记]如何测试用户接受度?