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

文章目录

  • 日志实现
    • 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=NULLreturn 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 1024time_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 clientserver:server.ccg++ -o $@ $^ -g -std=c++11mkdir log
client:client.ccg++ -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;}elsebreak;}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 0664enum
{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.mzph.cn/news/663524.shtml

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

相关文章

【软件工程】建模工具之开发各阶段绘图——UML2.0常用图实践技巧(功能用例图、静态类图、动态序列图状态图活动图)

更多示例图片可以参考&#xff1a;&#xff08;除了常见的流程图&#xff0c;其他都有&#xff09; 概念&#xff1a;类图 静态&#xff1a;用例图 动态&#xff1a;顺序图&状态图&活动图 1、【面向对象】UML类图、用例图、顺序图、活动图、状态图、通信图、构件图、部…

Redis核心技术与实战【学习笔记】 - 12.Redis删除数据后,为什么内存占用率还是很高?

前言 在使用 Redis 是&#xff0c;经常会遇到一个问题&#xff1a;明明做了数据删除&#xff0c;数据量不大&#xff0c;但是 使用 top 命令查看时&#xff0c;发现 Redis 还是占用了很多内存。 这是因为&#xff0c;当删除数据后&#xff0c;Redis 释放的内存空间会由内存分…

《数字化运维路线图》第三部分-数字化运维转型平台 震撼发布!

数字化转型已不再是企业追求效益最大化的手段&#xff0c;而是成为经济发展变革、提升国家数字竞争的核心动力。在此背景下&#xff0c;博睿数据继续发力&#xff0c;隆重推出「数字化运维转型平台」&#xff0c;汇聚了我们对数字化转型的深刻洞见与实践经验&#xff0c;以期为…

༺༽༾ཊ—Unity之-01-工厂方法模式—ཏ༿༼༻

首先创建一个项目&#xff0c; 在这个初始界面我们需要做一些准备工作&#xff0c; 建基础通用文件夹&#xff0c; 创建一个Plane 重置后 缩放100倍 加一个颜色&#xff0c; 任务&#xff1a;使用工厂方法模式 创建 飞船模型&#xff0c; 首先资源商店下载飞船模型&#xff0c…

《区块链简易速速上手小册》第6章:区块链在金融服务领域的应用(2024 最新版)

文章目录 6.1 金融服务中的区块链6.1.1 金融服务中区块链的基础6.1.2 主要案例&#xff1a;跨境支付6.1.3 拓展案例 1&#xff1a;去中心化金融&#xff08;DeFi&#xff09;6.1.4 拓展案例 2&#xff1a;代币化资产 6.2 区块链在支付系统中的作用6.2.1 支付系统中区块链的基础…

Linux - iptables 防火墙

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

专业数据治理:数据中台系统塑造企业未来的数字化运营管理新秩序

随着信息化进程的快速推进&#xff0c;数据已然成为企业最为宝贵的资产。对于众多企业而言&#xff0c;如何有效整合、治理以及充分利用这些数据&#xff0c;使之成为推动业务发展的引擎&#xff0c;成为当前难题。数据中台应运而生&#xff0c;它被认为是企业数字化转型的至关…

元素的显示与隐藏,精灵图,字体图标,CSSC三角

元素的显示与隐藏 类似网站广告&#xff0c;当我们点击关闭就不见了&#xff0c;但是我们重新刷新页面&#xff0c;会重新出现 本质&#xff1a;让元素在页面中隐藏或者显示出来。 1.display显示隐藏 2.visibility显示隐藏 3.overflow溢出显示隐藏 1.display属性&#xff08;…

远EC600E-CN LTE Standard模块硬件设计手册

EC600E-CN是一款LTE-FDD、LTE-TDD无线通信模块&#xff0c;支持LTE-FDD和LTE-TDD数据连接&#xff0c;可为客户在特定场景应用中提供语音功能。 模块封装紧凑&#xff0c;仅为22.9mm21.9mm2.4mm&#xff0c;能满足大部分M2M应用需求&#xff0c;例如自动化领域、智能计量、跟踪…

IP网络对讲系统高清可视寻呼话筒管理中心主机10寸大屏有线呼叫器监狱看守所监狱收费站可视对讲系统

SV-2017P网络可视话筒产品简介 产品特点 专业寻呼主机外形&#xff0c;桌面式设计&#xff0c;采用10.1寸高清IPS屏幕&#xff0c;分辨率1280*720&#xff0c;全虚拟按键加实体按键&#xff0c;外形美观大方&#xff1b;采用工业级4核嵌入式CPU芯片1G内存&#xff0c;保证系统…

arcgis自定义dem高程实现地形抬高 - 操作矢量,转tin、adf(tif),cesiumlab切高程服务

这次记录分享一下arcgis自定义高程全过程 /(ㄒoㄒ)/~~ 我的场景&#xff1a;前端实现地面抬高效果 自定义高程实现地形抬高 一、数据处理 - arcgis操作矢量1、准备工作&#xff08;可选&#xff09;2、绘制外围矢量&#xff08;可选&#xff09;3、操作矢量数据 二、创建tin - …

VUE PC端可拖动悬浮按钮

一、实现效果&#xff1a; 二、FloatButton.vue <template><div><div class"sssss"><div class"callback float" mousedown"down" touchstart"down" mousemove"move" touchmove"move" mous…

C语言——柔性数组

柔性数组概念&#xff1a; 这个概念你可能没听说过&#xff0c;但是这个概念确实存在&#xff0c;在C99中&#xff0c;结构体中最后一个成员允许是未知大小的数组&#xff0c;这就叫做【柔性数组】成员。 struct S {char c;int i;int arr[0];//未知大小的数组 - 柔性数组成员 }…

Java项目:基于SSM框架实现的西安旅游管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm811基于SSM框架实现的西安旅游管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&am…

Portainer访问远程Docker (TLS加密)

前言&#xff1a; docker的2375端口&#xff0c;出于安全性考虑即(Docker Remote API未授权访问漏洞)&#xff0c;是不开放的&#xff0c;如果想要管理远程docker&#xff0c;可以使用TLS机制来进行访问&#xff0c;这里以Portainer访问连接为例 文章参考&#xff1a;https://b…

单机搭建hadoop环境(包括hdfs、yarn、hive)

单机可以搭建伪分布式hadoop环境&#xff0c;用来测试和开发使用&#xff0c;hadoop包括&#xff1a; hdfs服务器 yarn服务器&#xff0c;yarn的前提是hdfs服务器&#xff0c; 在前面两个的基础上&#xff0c;课可以搭建hive服务器&#xff0c;不过hive不属于hadoop的必须部…

MacBook安装软件时允许任何来源的软件

MacBook安装软件时允许任何来源的软件 临时设置允许未知来源的app 当下载网上的软件并安装时,会安装失败, 因为MacOS默认只允许安装App Store上的软件 这时可以临时允许安装,如下设置 开启设置—->安全性与隐私—->未知来源的app 这种方式比较安全 设置允许任何来源…

计算机毕业设计 | SpringBoot 房屋租赁网 房屋租赁平台(附源码)

1&#xff0c;绪论 1.1 背景调研 在房地产行业持续火热的当今环境下&#xff0c;房地产行业和互联网行业协同发展&#xff0c;互相促进融合已经成为一种趋势和潮流。本项目实现了在线房产平台的功能&#xff0c;多种技术的灵活运用使得项目具备很好的用户体验感。 这个项目的…

2024年美国大学生数学建模比赛MCM问题A:资源可用性和性别比例-思路解析与代码解答

2024 MCM Problem A: Resource Availability and Sex Ratios 一、题目翻译 背景 虽然一些动物物种存在于通常的雄性或雌性性别之外&#xff0c;但大多数物种实质上是雄性或雌性。虽然许多物种在出生时的性别比例为1&#xff1a;1&#xff0c;但其他物种的性别比例并不均匀。…

【A题完整论文】2024美赛完整论文+代码参考(无偿分享)

A题&#xff1a;资源可用性和性别比例 一、问题分析 1.1 问题一分析 针对该问题&#xff0c;若七鳃鮼的性别比例受到外部环境因素的影响&#xff0c;那么这可能会导致种群大小和结构的变化。如果雌性在某些环境条件下更为优势&#xff0c;种群的增加可能对其他物种的竞争和资源…