【Linux】日志的实现——日志等级的分类、日志的实现和输出、日志在程序中的应用(以管道通信为例)

news2024/9/28 21:59:57

文章目录

  • 日志实现
    • 1.日志的介绍
    • 2.日志的制作(向屏幕直接打印)
      • 2.1获取时间
      • 2.2输出内容
      • 2.3打印方式
        • 2.3.1向单个文件打印
        • 2.3.2向分类文件打印
    • 3.日志的应用
      • 3.1以管道通信为例

日志实现

1.日志的介绍

  Linux日志是以时间线-事件的方式记录操作系统和应用的信息,通过日志我们可以很快的找到错误信息和解决问题的方法。 实际上,当系统发生问题时,我们首先要做的事就是去分析日志文件。Linux日志主要分为以下四类:应用日志:记录应用程序的日志信息。事件日志:记录系统事件的日志信息。服务日志:记录服务运行的日志信息。系统日志:记录系统运行状态的日志信息。

  Linux日志对于系统的安全和稳定运行至关重要。通过查看和分析日志文件,管理员可以诊断系统故障、追踪攻击者、审计用户行为等。在Linux系统中,日志文件通常存储在/var/log目录下,例如syslog文件就包含了系统所有的日志信息。可以使用各种命令来查看和解析这些日志文件,例如tail、grep等。

  
在这里插入图片描述
  
  Linux系统的日志有两个比较重要的作用是:审核和监测。 下面我们尝试写一个简单的linux日志,其中只包含时间、部分等级和日志内容。

            

2.日志的制作(向屏幕直接打印)

  和实现其他的类对象一样,日志本身也是一个类,提供各种各样的函数,在这里我们使用宏来定义日志的等级,日志类提供一个打印信息。以后可能会有很多的打印信息,所以在这里我们使用可变参数列表。

// 常规  调试  警告  错误  致命
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

// 实现日志类
class Log
{
public:
  	// 日志的信息     日志等级    输出的格式    可变参数
    void logmessage(int level, const char *format, ...)
    {}
};  

  

  这个sum函数表示使用可变参数列表实现累加操作:

  va_list s;:声明一个va_list类型的变量s,用于存储可变参数的列表。

  va_start(s,n);:初始化s,使其指向可变参数列表中的第一个参数。n是函数中已知的固定参数。

  sum+=va_arg(s,int);:在循环内部,使用va_arg宏从可变参数列表中提取下一个整数,并将其加到sum上。int指定了期望的参数类型。

  va_end(s);:完成对可变参数列表的处理,释放相关的资源。

//使用可变参数  可变参数左边至少有一个具体的参数
int sum(int n,...)
{
    va_list s;  //提取可变参数  char*
    va_start(s,n);

    int sum=0;
    while(n)
    {
        sum+=va_arg(s,int);  //类型不能作为参数传递,所以va_arg为宏
    }

    va_end(s);  //s=NULL
    return sum;
}

/*
cout<<sum(1,10)<<endl;  //10
cout<<sum(3,1,2,3)<<endl;  //6
cout<<sum(4,1,2,3,4)<<endl;  10
*/

  

2.1获取时间

在这里插入图片描述
  

  time_t t = time(nullptr); 这一行代码获取当前的时间,并将其存储在time_t类型的变量t中。time(nullptr)返回自1970年1月1日(称为UNIX纪元)以来的秒数。

  struct tm *ctime = localtime(&t);这一行代码将time_t类型的时间转换为本地时间,并将其存储在struct tm类型的指针ctime中。localtime函数返回一个指向tm结构体的指针,该结构体包含了本地时间的各个部分,如年、月、日、小时、分钟和秒。

  char leftbuffer[SIZE];这一行代码声明了一个字符数组leftbuffer,其大小由SIZE定义。这个数组将用于存储格式化后的时间字符串。
  

snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(), ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

  这一行代码使用snprintf函数将时间格式化为字符串并存储在leftbuffer中。

  %d-%d-%d 表示年份、月份和日期,例如“2023-09-13”。
  %d:%d:%d 表示小时、分钟和秒,例如“15:30:45”。

  ctime->tm_year + 1900、ctime->tm_mon + 1、ctime->tm_mday、ctime->tm_hour、ctime->tm_min和ctime->tm_sec是从前面获取的本地时间结构体中提取的各个部分。因为C语言的tm结构体中的年份是从1900年开始计数的,月份是从0开始计数的,所以需要加上这些偏移量来得到实际的年份和月份。

  通过这段代码我们可以获取当前的时间,将其格式化为一个字符串,并将这个字符串存储在leftbuffer数组中。

#define SIZE 1024

time_t t = time(nullptr);
struct tm *ctime = localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", 
			levelToString(level).c_str(),
            ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
            ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

  
  上面中的levelToString(level);我们在这里实现,通过写入的日志等级,我们进行一个简单的switch循环,即可将输入的日志等级转换为日志等级的字符串并且返回给函数levelToString(level);

// 获取日志等级的字符串
std::string levelToString(int level)
{
    switch (level)
    {
    case Info:
        return "Info";
    case Debug:
        return "Debug";
    case Warning:
        return "Warning";
    case Error:
        return "Error";
    case Fatal:
        return "Fatal";
    default:
        return "None";
    }
}

  

2.2输出内容

  va_list s;声明一个va_list类型的变量s,用于存储可变参数的列表。

  va_start(s, format);:初始化s,使其指向可变参数列表中的第一个参数。这里,format是第一个固定参数,它用于指定后面可变参数的格式。

  char rightbuffer[SIZE];:声明一个字符数组rightbuffer,其大小由SIZE定义。这个数组将用于存储格式化后的可变参数字符串。

  vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);:使用vsnprintf函数将可变参数格式化为字符串并存储在rightbuffer中。

  va_end(s);结束对可变参数列表的处理,释放相关的资源。

  char logtxt[SIZE * 2];:声明一个字符数组logtxt,其大小是SIZE * 2。这个数组将用于存储最终的日志文本。

  snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);:使用snprintf函数将leftbuffer和rightbuffer拼接为一个完整的日志文本,并存储在logtxt中。

  printf("%s", logtxt);:暂时将日志文本打印到标准输出(通常是显示器)。

  我们通过可变参数列表初始化一个字符指针,然后使用这个指针来格式化可变参数为一个字符串,并将这个字符串与左缓冲区的内容拼接为一个完整的日志文本,最后将这个日志文本打印出来。

// 用第一个形参初始化char*指针
va_list s;
va_start(s, format);  //const char *format
// 右边缓冲区
char rightbuffer[SIZE];
vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
va_end(s);

// 格式:默认部分+自定义部分
char logtxt[SIZE * 2];
snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

// 暂时打印  这里是向显示器中打印  后面实现向文件中打印
printf("%s", logtxt);

  

2.3打印方式

  以上就是日志向屏幕打印的代码实现,我们还可以实现单个文件或分类文件的打印。

  我们在输入和接受参数中加入一个打印方式函数,我们将打印方式函数先缺省为直接向屏幕打印,如果想要在文件中打印,我们只需要调用void Enable(int method)函数再传入想要打印的方式即可。

  #define LogFile "log.txt":定义了默认的日志文件名为"log.txt"。

  Log():类的默认构造函数,初始化时将打印方式设置为屏幕,并设置路径为"./log/"

  void printLog(int level, std::string logtxt):一个公共成员函数,根据设置的打印方式将日志信息输出到相应的目标。

  int printMethod;:一个私有整数变量,用于存储打印方式。

  std::string path;:一个私有字符串变量,用于存储打印到文件的路径信息。

// 向屏幕  单个文件  分类打印
#define Screen 1
#define Onefile 2
#define Classfile 3

// 日志文件
#define LogFile "log.txt"

class Log
{
public:
    // Log的默认构造打印方式是打印在屏幕上
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }

    // 打印的方式
    void Enable(int method)
    {
        printMethod = method;
    }
    
    // 日志的信息     日志等级  输出的格式  可变参数
    void logmessage(int level, const char *format, ...)
	{
		//......
	}

	// 按方式打印
    void printLog(int level, std::string logtxt)
    {
        switch (printMethod)
        {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            //printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            //printClassFile(level, logtxt);
            break;
        default:
            break;
        }
    }
    
private:
    int printMethod;  // 打印的方式
    std::string path; // 打印到文件中的路径信息
};

  

2.3.1向单个文件打印

  int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);:使用 open 系统调用打开一个文件。文件名是 _logname,打开模式是 O_WRONLY(只写模式)、O_CREAT(如果文件不存在则创建它)和 O_APPEND(每次写入都在文件末尾添加)。权限设置为 0666,意味着所有用户都有读写权限。

  write(fd, logtxt.c_str(), logtxt.size());使用 write 系统调用将日志信息写入文件。

  通过这个函数我们可以将传入的日志信息 logtxt 写入到由 path 和 logname 指定的文件中。如果文件打开失败,函数不会执行任何操作。

// 向单个文件中打印
void printOneFile(const std::string &logname, const std::string &logtxt)
{
    std::string _logname = path + logname;
    int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); 
  	// "log.txt"
    if (fd < 0)
        return;
    // 向文件中写入日志信息
    write(fd, logtxt.c_str(), logtxt.size());
    close(fd);
}

  

2.3.2向分类文件打印

  std::string filename = LogFile;:创建一个字符串 filename,并将其初始化为 LogFile(类的私有成员变量,代表默认日志文件名)。

  filename += levelToString(level);:调用一个名为 levelToString 的函数(该函数在代码中未给出),**将日志等级 level 转换为对应的字符串,并将该字符串添加到文件名中。**例如,如果 level 是 2,那么 filename 将变为 “log.txt.Debug”。

  printOneFile(filename, logtxt);:调用之前定义的 printOneFile 函数,将日志信息写入到与日志等级对应的文件中。

  通过这个函数我们可以将日志信息按照不同的日志等级分类打印到不同的文件中。 例如,所有等级为 “Debug” 的日志信息将被写入到 “log.txt.Debug” 文件中,所有等级为 “Warning” 的日志信息将被写入到 “log.txt.Warning” 文件中,以此类推。

// 向文件分类打印
void printClassFile(int level, const std::string &logtxt)
{
    std::string filename = LogFile;
    filename += ".";
    filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"
    printOneFile(filename, logtxt);
}

  

3.日志的应用

3.1以管道通信为例

  使用我们以前写的管道通信的程序为例:

在这里插入图片描述

  
在这里插入图片描述

  
Makefile

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -g -std=c++11
	mkdir log
client:client.cc
	g++ -o $@ $^ -g -std=c++11

.PHONY:clean
clean:
	rm -f server client 
	rmdir log

  

client.cc

#include <iostream>
#include "comm.hpp"

using namespace std;

int main()
{
    int fd = open(FIFO_FILE, O_WRONLY);
    if(fd < 0)
    {
        perror("open");
        exit(FIFO_OPEN_ERR);
    }

    cout << "client open file done" << endl;

    string line;
    while(true)
    {
        cout << "Please Enter@ ";
        getline(cin, line);

        write(fd, line.c_str(), line.size());
    }

    close(fd);
    return 0;
}

  

server.cc

#include "comm.hpp"
#include "log.hpp"

using namespace std;

// 管理管道文件
int main()
{
    Init init;
    Log log;
    //log.Enable(Onefile);

    // 打开管道
    int fd = open(FIFO_FILE, O_RDONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!
    if (fd < 0)
    {
        log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);
        exit(FIFO_OPEN_ERR);
    }

    log(Info, "server open file done, error string: %s, error code: %d", strerror(errno), errno);
    log(Warning, "server open file done, error string: %s, error code: %d", strerror(errno), errno);
    log(Fatal, "server open file done, error string: %s, error code: %d", strerror(errno), errno);
    log(Debug, "server open file done, error string: %s, error code: %d", strerror(errno), errno);


    // 开始通信
    while (true)
    {
        char buffer[1024] = {0};
        int x = read(fd, buffer, sizeof(buffer));
        if (x > 0)
        {
            buffer[x] = 0;
            cout << "client say# " << buffer << endl;
        }
        else if (x == 0)
        {
            log(Debug, "client quit, me too!, error string: %s, error code: %d", strerror(errno), errno);
            break;
        }
        else
            break;
    }

    close(fd);
    return 0;
}

  

Log.hpp

#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define SIZE 1024

// 常规  调试  警告  错误  致命
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

// 向屏幕  单个文件  分类打印
#define Screen 1
#define Onefile 2
#define Classfile 3

// 日志文件
#define LogFile "log.txt"

// 实现日志类
class Log
{
public:
    // Log的默认构造打印方式是打印在屏幕上
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }

    // 打印的方式
    void Enable(int method)
    {
        printMethod = method;
    }

    // 获取日志等级的字符串
    std::string levelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "None";
        }
    }

    // 日志的信息     日志等级  输出的格式  可变参数
    void logmessage(int level, const char *format, ...)
    {
        // 获取当前的时间
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);
        // std::cout<<time(nullptr)<<std::endl;

        // 左边缓冲区
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
                 ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        // 用第一个形参初始化char*指针
        va_list s;
        va_start(s, format);
        // 右边缓冲区
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        // 格式:默认部分+自定义部分
        char logtxt[SIZE * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

        // 暂时打印  这里是向显示器中打印  下面实现向文件中打印
        // printf("%s", logtxt);

        // 多种方式打印
        printLog(level, logtxt);
    }

    // 按方式打印
    void printLog(int level, std::string logtxt)
    {
        switch (printMethod)
        {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            printClassFile(level, logtxt);
            break;
        default:
            break;
        }
    }

    // 向单个文件中打印
    void printOneFile(const std::string &logname, const std::string &logtxt)
    {
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"
        if (fd < 0)
            return;
        // 向文件中写入日志信息
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }

    // 按文件分类打印
    void printClassFile(int level, const std::string &logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"
        printOneFile(filename, logtxt);
    }

    //运算符重载
    void operator()(int level, const char *format, ...)
    {
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
                 ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        // 格式:默认部分+自定义部分
        char logtxt[SIZE * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

        // printf("%s", logtxt); // 暂时打印
        printLog(level, logtxt);
    }

    // Log的析构函数
    ~Log()
    {}

private:
    int printMethod;  // 打印的方式
    std::string path; // 打印到文件中的路径信息
};

  

comm.hpp

#pragma once

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define FIFO_FILE "./myfifo"
#define MODE 0664

enum
{
    FIFO_CREATE_ERR = 1,
    FIFO_DELETE_ERR,
    FIFO_OPEN_ERR
};

class Init
{
public:
    Init()
    {
        // 创建管道
        int n = mkfifo(FIFO_FILE, MODE);
        if (n == -1)
        {
            perror("mkfifo");
            exit(FIFO_CREATE_ERR);
        }
    }
    ~Init()
    {

        int m = unlink(FIFO_FILE);
        if (m == -1)
        {
            perror("unlink");
            exit(FIFO_DELETE_ERR);
        }
    }
};

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

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

相关文章

本体论(ontology)在工业4.0中的应用

信息技术中的本体与哲学的本体论是不同的&#xff0c;它代表了某个专业领域的基本概念&#xff0c;它们在智能制造和工业4.0 中具有不可或缺的作用&#xff0c;为了实现人与机器&#xff0c;机器与机器之间的确定性操作。一个标准化的&#xff0c;精确定义的本体服务是非常重要…

进程信号-

一.信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 二.信号的产生 1.通过键盘进行信号的产生。&#xff08;1-31多数都是杀掉进程&#xff09; &#xff08;ctrl c&#xff1a;向前台进程发送2号信号&#xff0c;杀掉进程&#xff09; &#xff0…

word调整论文格式的记录

页眉的分章显示内容 效果&#xff1a; 步骤&#xff1a; 确保“显示/隐藏的标记”符号打开点亮 前提是章节前面有“分节符&#xff08;下一页&#xff09;”&#xff0c;没有则添加&#xff0c;在菜单栏“布局”——》“下一页” 添加页眉&#xff0c;双击页眉&#xff0c;选…

【DevOps】产品需求文档(PRD)与常见原型软件

文章目录 1、PRD介绍1.1、概述1.2、前提条件1.3、主要目的1.4、关键内容1.5、表述方式1.6、需求评审人员1.7、一般内容结构 2、需求流程3、常见原型软件3.1、Word3.2、Axure3.2.1、详细介绍3.2.2、应用分类3.2.3、优缺点 3.3、摹客RP3.4、蓝湖3.5、GUI Design Studio 1、PRD介绍…

基于SpringBoot Vue单位考勤管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

25.云原生之ArgoCD-app of apps模式

文章目录 app of apps 模式介绍app如何管理apphelm方式管理kustomize方式管理 app of apps 模式介绍 通过一个app来管理其他app&#xff0c;当有多个项目要发布创建多个app比较麻烦&#xff0c;此时可以创建一个管理app&#xff0c;管理app创建后会创建其他app。比较适合项目环…

在 Windows 10 上使用 Visual Studio 2022 进行 C++ 桌面开发

工具下载链接&#xff1a;https://pan.quark.cn/s/c70b23901ccb 环境介绍 在今天的快速发展的软件开发行业中&#xff0c;选择合适的开发环境是非常关键的一步。对于C开发人员来说&#xff0c;Visual Studio 2022&#xff08;VS2022&#xff09;是一个强大的集成开发环境&…

Vue2+ElementUI 弹窗全局拖拽 支持放大缩小

拖拽组件 dialogDrag.vue <template><div></div> </template> <script>export default {name: dialogDrag,data() {return {originalWidth: null,originalHeight: null}},created() {this.$nextTick(()>{this.dialogDrag()})},mounted() {}…

Opencv(C++)学习 之RV1126平台的OPENCV交叉编译

本文特点&#xff1a;网上已经有了很多opencv移植RV1106的文章&#xff0c;本文主要记录基于cmake-gui编译&#xff0c;碰到的报错&#xff0c;及解决报错问题的方法&#xff0c;同时简单总结一些配置项相关的知识。 一、环境&#xff1a; ubuntu18 x64 RV1126交叉编译工具链 …

【服务器搭建】快速完成幻兽帕鲁服务器的搭建及部署【零基础上手】

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 教程详戳&#xff1a;不需要懂技术&#xff0c;1分钟幻兽帕鲁服…

unity3d的海盗王白银城演示

这是一个外网上的下载的海盗王unity3d制作的白银城演示场景。 地图只含有白银城区&#xff0c;没有野外和怪物。 当然也没有服务器端的。 我对灯光、摄像头、天空背景等做过调整&#xff0c;使它显示起来比较鲜丽。 它的模型和贴图是直接拿了海盗的&#xff0c;没有做过优化调整…

AI监控+智能充电桩系统如何缓解新能源汽车充电难问题

在新能源汽车行业的快速发展中&#xff0c;充电桩作为重要的配套设施&#xff0c;其建设和发展至关重要。随着新能源汽车销量的增长&#xff0c;补能需求也日益迫切&#xff0c;这为充电桩行业的发展提供了巨大的机遇。然而&#xff0c;充电桩行业在快速发展的同时&#xff0c;…

Day17、18、19学习记录

#c语言知识 内存管理 1.作用域 &#xff08;1&#xff09;代码块作用域&#xff08;代码块是{}之间的一段代码&#xff09; &#xff08;2&#xff09;函数作用域 &#xff08;3&#xff09;文件作用域 2.局部变量&#xff08;自动变量auto&#xff09;&#xff1a; 在函…

【C语言】异常处理 | assert函数 | errno错误码

文章目录 C语言传统的处理错误的方式1. 终止程序&#xff08;例如使用 assert&#xff09;2. 返回/设置错误码手动实现C语言库函数内置的错误码Linux系统调用内置的错误码 C语言传统的处理错误的方式 C语言传统的处理错误的方式主要包括assert终止程序和返回或设置错误码两种方…

Linux系统安全:安全技术 和 防火墙

一、安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全决策依据,类 似于监控…

flinkjar开发 自定义函数

编写自定义加密函数&#xff0c;继承ScalarFunction类&#xff0c;实现eval方法&#xff0c;参数个数类型和返回值根据业务来自定义。 import org.apache.flink.table.functions.ScalarFunction; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax…

Axure 动态面板初使用 - 实现简单的Banner图轮播效果

使用工具版本 Axure 9 实现的效果 步骤过程 1、打开Axure工具&#xff0c;从元件库拖个动态面板到空白页&#xff1b; 2、给面板设置一个常用的banner尺寸&#xff0c;举个栗子&#xff1a;343151(移动端我常用的banner尺寸)&#xff0c;顺便给它起个名字&#xff0c;就叫…

探讨深浅拷贝在js加密中的运用

深浅拷贝是JavaScript中常用的概念&#xff0c;用于复制对象或数组。它们在处理数据时有不同的用途&#xff0c;适用于不同的场景。在本文中&#xff0c;我们将详细介绍深浅拷贝的概念&#xff0c;提供案例代码&#xff0c;并探讨它们在JavaScript中的应用场景&#xff0c;以及…

演讲回顾:如何为大规模研发团队加速CI构建,实现高效流水线

近日&#xff0c;龙智联合Atlassian举办的DevSecOps研讨会年终专场”趋势展望与实战探讨&#xff1a;如何打好DevOps基础、赋能创新”在上海圆满落幕。龙智Atlassian技术与顾问咨询团队&#xff0c;以及清晖、JamaSoftware、CloudBees等生态伙伴的嘉宾发表了主题演讲&#xff0…

Mysql的BufferPool

Mysql的BufferPool Mysql是一个存储数据到磁盘的进程&#xff0c;但是磁盘的速度难以与CPU相比&#xff0c;所以InnoDB存储引擎在处理客户端的请求时&#xff0c;当需要访问某个页的数据时&#xff0c;就会把完整的页的数据全部加载到内存中。将整个页加载到内存中后就可以进行…