linux基于systemd自启守护进程 systemctl自定义服务傻瓜式教程
系统服务
书接上文: linux自启任务详解
演示系统:ubuntu 20.04
开发部署项目的时候常常有这样的场景: 业务功能以后台服务的形式提供,部署完成后可以随着系统的重启而自动启动;服务异常挂掉后可以再次拉起
这个功能在ubuntu系统中通常由systemd提供
如果仅仅需要达成上述的场景功能,则systemd的自定义服务就可以满足
什么是systemd
systemd:系统和服务管理器
- 功能:
systemd 是一个初始化系统(init system)和服务管理器,它负责在 Linux 系统启动时启动系统的核心服务和进程。它的任务是管理系统引导、服务管理、进程监控、资源管理等。
systemd 提供了服务启动、停止、重启、日志记录等功能,并管理系统的运行状态。 - 作用:
启动和管理系统服务:systemd 会在系统启动时根据配置文件(服务单元文件)启动必要的系统服务(例如网络、日志记录、定时任务等)。
管理进程和依赖关系:systemd 确保服务按照正确的顺序启动,并且根据需要重启或停止。
资源管理:通过 cgroups(控制组)和其他技术,systemd 能够限制服务对 CPU、内存等资源的使用。 - 配置文件:
systemd 使用以 .service 结尾的单元文件(unit files)来定义服务。每个服务有一个单独的配置文件,这些文件描述了服务如何启动、停止、重启等。
例如,/etc/systemd/system/ 和 /lib/systemd/system/ 目录下存放着这些单元文件。
什么是systemctl
systemctl:管理 systemd 的命令行工具
- 功能:
systemctl 是与 systemd 配合使用的命令行工具,用于启动、停止、重新启动、查看、启用或禁用 systemd 管理的服务。它是用户与 systemd 交互的主要方式。 - 作用:
启动和停止服务:通过 systemctl 命令,你可以启动、停止或重启任何由 systemd 管理的服务。
查看服务状态:systemctl status 命令可以用来查看服务的当前状态,帮助管理员诊断服务是否正常运行。
管理系统:systemctl 也可用于关闭、重启、挂起系统等操作。
启用/禁用服务:systemctl enable 用于设置服务开机启动,systemctl disable 用于禁止服务开机启动。 - 常见命令示例:
- 启动服务:systemctl start <service_name>
- 停止服务:systemctl stop <service_name>
- 查看服务状态:systemctl status <service_name>
- 重启服务:systemctl restart <service_name>
- 设置服务开机启动:systemctl enable <service_name>
- 设置服务不开机启动:systemctl disable <service_name>
关系
- systemd 是基础,systemctl 是工具:
systemd 是系统和服务的管理器,它负责实际的服务管理、进程监控、资源分配等。而 systemctl 是一个命令行工具,用户通过它与 systemd 进行交互,执行启动、停止、查看状态等操作。
可以理解为,systemd 是背后的系统管理框架,而 systemctl 是用户与其交互的接口。 - systemctl 控制 systemd:
systemctl 是通过向 systemd 发送指令来管理服务和系统。例如,当你通过 systemctl start <service_name> 启动一个服务时,systemctl 会告诉 systemd 启动该服务,systemd 会根据服务的配置文件启动服务并管理它。
自定义自启动服务
linux自启任务详解
想要自定义一个自启服务,需要两个东西:可执行程序(我们自己的后台业务程序)和systemd的服务脚本
假设我们自己的业务程序名为:test_demo,服务脚本名为:test_demo.service
当然了这个程序仅做演示比较简单,仅有一个test_demo_main.c文件,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>const char * filePath = "/home/lijilei/1.txt";
const char * text = "hello world\n";
const char * textend = "end lalala\n";
int g_count = 0;int main(int argc,char**argv)
{FILE *fp = NULL;fp = fopen(filePath,"a+");assert(fp > 0);while(true){sleep(6);fwrite(text, strlen(text),1,fp);fflush(fp); ++g_count;if(g_count > 10){fwrite(textend, strlen(textend),1,fp);break;}}fprintf(fp,"我要写东西: %s","东西");fflush(fp);fclose(fp);return 0;}
使用cc -o test_demo test_demo_main.c
可编译出test_demo程序
该演示程序逻辑相当简单:打开一个文件/home/lijilei/1.txt,向文件中分10次写入内容,然后退出
test_demo.service文件也相当简单
#move this file to /etc/systemd/system/
[Unit]
Description=Start up test_demo[Service]
Type=simple
ExecStart=/home/lijilei/xlib_xdnd/test_demo
Restart=on-failure[Install]
WantedBy=multi-user.target
脚本被systemd执行的时候会拉起ExecStart指定路径下的/home/lijilei/xlib_xdnd/test_demo程序;
将脚本放到/etc/systemd/system/目录下,按循序执行如下指令:
- sudo systemctl enable test_demo.service 启用服务,以便在系统启动时自动启动
- sudo systemctl start test_demo.service 启动test_demo.service服务,也就是变相的拉起配置的ExecStart=/home/lijilei/xlib_xdnd/test_demo程序
- sudo systemctl status test_demo.service 停止服务
当修改.service文件后执行
- sudo systemctl daemon-reload 当有修改.service文件时,需重新加载
上述的配置已经可以实现开机自启一个服务运行
自定义自启动守护进程
自启动守护进程的业务场景
在上述自启服务的基础上,将业务服务程序改为守护进程程序,使用守护进程去守护目标业务程序会更方便的控制业务程序的生命周期;
比如将守护进程改为看门狗程序,业务程序一直给看门狗发指令(喂狗),当业务程序因为业务崩溃了,则守护进程(看门狗主动拉起)业务程序,当然了我这里不会演示如何写一个看门狗程序,这里用定时查看进程快照的方式检测目标业务程序是否在执行,如果不在执行则拉起
什么是守护进程
守护进程是个孤儿进程,它的运行脱离了进程组的管控,无法接受进程退出信号,会一直运行在后台直到本身发生崩溃退出
为什么使用守护进程
守护进程的特性决定了它不会因为任何退出信号而关闭,所以适合用来执行监控任务,只要守护进程自带的业务逻辑足够简单,那守护进程将永远运行,直到系统关机,能让守护进程退出的方法只有三种
- 系统关机
- 找到守护进程的pid,手动kill
- 守护进程因自己的运行bug崩溃退出
因为systemd的功能,我们可以克服第一个方法跟第三个方法导致的守护进程因关机或崩溃而无法再次运行的问题
怎么写一个守护进程
这里创建一个名为daemond.c的文件,文件内容如下:
// daemon.c
#include <stdio.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <assert.h>static FILE *g_fp = NULL;
static time_t g_now;
static const char* PIDFile = "/var/daemond.pid";
//static const char* LOCKDir = "/var/run/daemond";
static const char* LOGFile = "/var/log/daemond.txt";//看护的程序名字,可以是多个
static const char* PROCESSName1 = "test_demo";
static const char* PROCESSName2 = NULL;static int init_daemon(void)
{pid_t pid;int i;pid = fork();if(pid > 0){//第一步,结束父进程,使得子进程成为后台exit(0);}else if(pid < 0){return -1;}/*第二步建立一个新的进程组,在这个新的进程组中,子进程成为这个进程组的首进程,以使该进程脱离所用终端*/setsid();/*再次新建一个子进程,退出父进程,保证该进程不是进程组长,同时让该进程无法再打开一个新的终端*/pid = fork();if(pid > 0){exit(0);}else if(pid < 0){return -1;}//第三步:关闭所用从父进程继承的不再需要的文件描述符for(i = 0;i < NOFILE;close(i++));//第四步:改变工作目录,使得进程不与任何文件系统联系chdir("/");//第五步:将文件屏蔽字设置为0umask(0);//第六步:忽略SIGCHLD信号 执行第二步后就不需要执行该步骤signal(SIGCHLD,SIG_IGN);// 1. 忽略其他异常信号// 忽略子进程结束信号,防止产生僵尸进程//signal(SIGCLD, SIG_IGN);// 忽略管道破裂信号,防止程序因向已关闭的管道写入而异常退出//signal(SIGPIPE, SIG_IGN);// 忽略停止信号,守护进程通常不应被外部信号随意停止//signal(SIGSTOP, SIG_IGN);return 0;
}static int program_running_number(const char *prog)
{if(prog == NULL) {return 0;}FILE *fp;int count = 0;char buf[8] = {0};char command[128];snprintf(command, sizeof(command), \"ps -ef | grep -v grep | grep -w -c %s", prog);command[sizeof(command) - 1] = '\0';fp = popen(command, "r");if (fp == NULL) {time(&g_now);fprintf(g_fp,"系统时间:\t%s\t\t execute %s failed: %s",ctime(&g_now),command, strerror(errno));fflush(g_fp);return 0;}if (fgets(buf, sizeof(buf), fp)) {count = atoi(buf);}pclose(fp);return count;
}static int createPIDFile(const char* File)
{umask(000);FILE *pidfile = fopen(File, "w");if (pidfile) {fprintf(pidfile, "%d", getpid());fclose(pidfile);return 0;} else {return -1;}
}static int createLOCKDir(const char* dir)
{char cmd[256] = {0};sprintf(cmd,"mkdir %s",dir);int ret = system(cmd);if (ret == 0) {return 0;} else {return -1;}
}static void watchProcess(const char** prcsessList)
{for (const char **prog = prcsessList; *prog; prog++) {if (program_running_number(*prog) > 0) {//fprintf(g_fp,"%s is running.\n", *prog);} else {time(&g_now);fprintf(g_fp,"系统时间:%s %s isn't running.\n",ctime(&g_now),*prog);fflush(g_fp);//再次执行唤起目标程序指令(可替换拉起进程指令)char cmd[256] = {0};sprintf(cmd,"sudo systemctl start %s.service",*prog);fprintf(g_fp,"执行命令: %s\n",cmd);int value = system(cmd);if (value == -1) {time(&g_now);fprintf(g_fp,"系统时间:%s %s : system() failed\n",ctime(&g_now),cmd);fflush(g_fp);} else if (WIFEXITED(value)) {time(&g_now);fprintf(g_fp,"系统时间:%s %s executed successfully with exit code %d: succeed\n",ctime(&g_now),cmd,WEXITSTATUS(value));fflush(g_fp);} else if (WIFSIGNALED(value)) {time(&g_now);fprintf(g_fp,"系统时间:%s %s : terminated by signal %d\n",ctime(&g_now),cmd,WTERMSIG(value));fflush(g_fp);} else {time(&g_now);fprintf(g_fp,"系统时间:%s %s : Unknown status\n",ctime(&g_now),cmd);fflush(g_fp);printf("Unknown status\n");}} }
}int main()
{init_daemon(); createPIDFile(PIDFile);//createLOCKDir(LOCKDir);while(1) {sleep(3);g_fp = fopen(LOGFile,"a+");if(g_fp == NULL) {return -1;}const char *program_name_list[] = {PROCESSName1, PROCESSName2};//这里修改进程看护逻辑watchProcess(program_name_list);fflush(g_fp);fclose(g_fp);}return 0;
}
使用cc -o daemond daemon.c
可编译出daemond守护进程程序
该daemond逻辑比较简单,就是负责监视test_demo程序,如果test_demo程序退出了就调用systemctl指令,执行test_demo.service,再次拉起test_demo
daemond.service的写法就稍微跟test_demo.service不同了
#move this file to /etc/systemd/system/
[Unit]
Description=Start up daemond
After=network.target
[Service]
User=root
Group=root
ExecStart=/home/lijilei/xlib_xdnd/daemond --single-instance
#当进程退出时自动重启
Restart=always
#适用于后台运行的服务,systemd 等待父进程退出,并且通过 PID 文件确认进程启动
Type=forking
#适用于后台运行的服务,systemd 等待父进程退出,并且通过 PID 文件确认进程启动
PIDFile=/var/daemond.pid
#只终止主进程,不终止子进程
KillMode=process
#RestartSec=5 #服务崩溃后会等待 5 秒钟再重启
#StartLimitIntervalSec=10 #定义了一个 10 秒的时间窗口
#StartLimitBurst=1 #在 10 秒内,服务最多重启 1 次。如果超过这个次数,systemd 将不会再重启服务
#删除PID文件
ExecStopPost=/bin/rm -f /var/daemond.pid
#删除日志文件
ExecStopPost=/bin/rm -f /var/log/daemond.txt
[Install]
WantedBy=multi-user.target
将脚本放到/etc/systemd/system/目录下,按顺序执行如下指令:
- sudo systemctl enable daemond.service 启用服务,以便在系统启动时自动启动
- sudo systemctl start daemond.service daemond.service服务,也就是变相的拉起配置的/home/lijilei/xlib_xdnd/daemond程序
执行效果
把test_demo.service和daemond.service都加入开机自启后会出现如下现象:
- test_demo.service会拉起test_demo程序
- test_demo程序在完成打印后退出
- daemond查找进程快照发现test_demo退出,就执行systemctl脚本test_demo.service
- test_demo.service会拉起test_demo程序
- …如此反复执行
查看下daemon.service的执行状态
$ sudo systemctl status daemond.service ● daemond.service - Start up daemondLoaded: loaded (/etc/systemd/system/daemond.service; enabled; vendor preset: enabled)Active: active (running) since Fri 2024-11-22 01:43:28 UTC; 2 weeks 0 days agoMain PID: 125749 (daemond)Tasks: 1 (limit: 14203)Memory: 13.9MCGroup: /system.slice/daemond.service└─125749 /home/lijilei/xlib_xdnd/daemond --single-instanceWarning: journal has been rotated since unit was started, output may be incomplete.
发现这个服务已经连续运行两周了
查看下1.txt内容:
发现已经打印了20几万行信息了
附录
如果你在 systemd 单元文件中使用了其他不熟悉或不常见的配置项,建议通过以下命令来验证服务单元文件的正确性:
- sudo systemd-analyze verify /etc/systemd/system/your_service.service
这个框架有个问题就是daemon在调用system()函数时能执行但是返回值是-1,猜测是由systemctl导致的.后面我再研究研究
以上
相关文章:
linux基于systemd自启守护进程 systemctl自定义服务傻瓜式教程
系统服务 书接上文: linux自启任务详解 演示系统:ubuntu 20.04 开发部署项目的时候常常有这样的场景: 业务功能以后台服务的形式提供,部署完成后可以随着系统的重启而自动启动;服务异常挂掉后可以再次拉起 这个功能在ubuntu系统中通常由systemd提供 如果仅仅需要达成上述的场…...
SparkSQL编程实践
文章目录 SparkSQL编程实践1.1. 编程模型介绍1.2. SparkSQL编程1.2.1. 第三方库安装1.2.2. SparkSQL程序的结构1.2.3. SparkSQL执行模式1.2.3.1. Local模式1.2.3.2. 集群模式 1.2.4. 数据加载1.2.4.1. 通过RDD创建DataFrame1.2.4.2. 通过读取数据外部数据创建DataFrame标准读取…...
模型训练数据-MinerU一款Pdf转Markdown软件
模型训练数据-MinerU一款Pdf转Markdown软件-说明 简介: MinerU是什么 MinerU是上海人工智能实验室OpenDataLab团队推出的开源智能数据提取工具,专注于复杂PDF文档的高效解析与提取。MinerU能将包含图片、公式、表格等元素的多模态PDF文档转化为易于分析…...
shell基础用法
shell基础知识 shell中的多行注释 :<<EOF read echo $REPLY # read不指定变量,则默认写入$REPLY EOF # :<<EOF ...EOF 多行注释,EOF可以替换为!# 等文件目录和执行目录 echo $0$0 # ./demo.sh echo $0的realpath$(realpath…...
Redisson分布式锁
概览 个人博客源地址 Redisson不只是一个 Java Redis 客户端,它是一个以内存 Redis 服务器作为后端的处理 Java 对象(如 java.util.List, java.util.Map, java.util.Set, java.util.concurrent.locks.Lock 等)的一个框架。 Redisson提供了使用Redis的最简单和最…...
【C语言--趣味游戏系列】--电脑关机整蛊小游戏
前言: 老铁们,还是那句话,学习很苦游戏来补, 为了提高大家与朋友之间的友谊,博主在这里分享一个电脑关机的恶作剧小游戏,快拿去试试吧!!! 目录: 1.电脑关机代…...
C#实现一个HttpClient集成通义千问-开发前准备
集成一个在线大模型(如通义千问),来开发一个chat对话类型的ai应用,我需要先了解OpenAI的API文档,请求和返回的参数都是以相关接口文档的标准进行的 相关文档 OpenAI API文档 https://platform.openai.com/docs/api-…...
二叉树优选算法(一)
一、根据二叉树创建字符串 题目介绍: 给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。 空节点使用一对空括号对 "()" 表示,转化后需…...
单片机C51--笔记8-STC89C51RC/RD-IIC协议
一、概述 IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双 工同步通信方式。 特点 简单性和有效性。 由于接口直接在组件之上,因此IIC总线占用的空间非常小…...
HttpUtil的get和post请求
Http工具类 import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.ht…...
leetcode 二进制数转字符串
1.题目要求: 2.题目代码: class Solution { public:string printBin(double num) {string result;double compare_value 1.0;//先给把0和.赋值给result;result.push_back(0);result.push_back(.);while(result.size() < 33){//利用十进制转换成二进制的方法//1.先给num …...
前端项目使用gitlab-cicd+docker实现自动化部署
GitLab CI/CD 是一个强大的工具,可以实现项目的自动化部署流程,从代码提交到部署只需几个步骤。本文将带你配置 GitLab CI/CD 完成一个前端项目的自动化部署。 前言 为什么使用cicddocker? 目前我们公司开发环境使用的shell脚本部署&#…...
【Linux】进程
🌻个人主页:路飞雪吖~ 🌠专栏:Linux 目录 一、冯诺依曼体系结构 🌟系统调用和库函数概念 二、操作系统OS 三、进程 🌟查看进程 🌟通过系统调用获取进程标示符 🌟通过系统调用创…...
transformers生成式对话机器人
简介 生成式对话机器人是一种先进的人工智能系统,它能够通过学习大量的自然语言数据来模拟人类进行开放、连贯且创造性的对话。与基于规则或检索式的聊天机器人不同,生成式对话机器人并不局限于预定义的回答集,而是可以根据对话上下文动态地…...
Text2SQL(NL2sql)对话数据库:设计、实现细节与挑战
Text2SQL(NL2sql)对话数据库:设计、实现细节与挑战 前言1.何为Text2SQL(NL2sql)2.Text2SQL结构与挑战3.金融领域实际业务场景4.注意事项5.总结 前言 随着信息技术的迅猛发展,人机交互的方式也在不断演进。…...
C# 关于加密技术以及应用(二)
AES(Advanced Encryption Standard)和 RSA(Rivest-Shamir-Adleman)是两种不同的加密算法,它们各自有特定的使用场景和优势。下面是它们的主要区别和适用场景: AES(高级加密标准) 特…...
四十四:Web如何关闭会话
在Web应用中,关闭会话(Session Termination)是一个重要的机制,用于确保用户的会话状态被安全地终止。无论是用户主动退出登录还是因超时被动登出,正确地管理会话关闭有助于提升安全性并释放服务器资源。 一、为什么需…...
在wsl2中安装archlinux
在之前的博客中,我介绍了如何在虚拟机或者真实机上安装archlinux并且进行一定的配置,但是实际上Linux不管怎么配置在日常使用中都没有Windows简单便利,在开发有关Linux的程序时过去用虚拟机或者直接在Windows上使用ssh在远程服务器上进行开发…...
在Goland中对goroutine协程断点调试
在Goland中对goroutine协程断点调试 环境: Goland 参考了 chatgpt 的回复 进行断点调试的代码 package mainimport ("fmt""sync""time" )// worker 模拟处理任务 func worker(id int, wg *sync.WaitGroup) {defer wg.Done() // 确保任务完成后…...
最长连续递增序列
问题分解 1:要求 要求找到最长的连续递增子序列,即在原数组中位置连续且数值严格递增的一段序列 2:输入和输出 输入是一个未经排序的整数数组nums 输出是该数组中最长连续递增子序列的长度 3:边界调节 数组为空则长度为0 …...
apt 包 源 的维护 和缓存 命令
APT 包源维护命令 更新软件包列表: sudo apt update:从配置的软件源中获取最新的软件包信息。这是安装、升级或删除软件包前通常要执行的步骤,以确保使用的是最新的软件包信息。 升级软件包: sudo apt upgrade:升级系…...
【排序方法的总结】
在数据结构中常见的排序方法有: 插入排序、交换排序、选择排序、归并排序和基数排序等。 插入排序 特点: 简单直观,对于小规模的数据排序效率较高。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后…...
工作中常用springboot启动后执行的方法
前言: 工作中难免会遇到一些,程序启动之后需要提前执行的需求。 例如: 初始化缓存:在启动时加载必要的缓存数据。定时任务创建或启动:程序启动后创建或启动定时任务。程序启动完成通知:程序启动完成后通…...
QT 中使用 QTableView 和 QStandardItemModel 实现将数据导出到Excel 和 从Excel导入到 QTableView 的功能
简介 在Qt中,使用QTableView和QStandardItemModel来实现将数据导出到Excel和从Excel导入到QTableView的功能,而不使用第三方库(如QXlsx)。 效果 将 QTableView 中的数据导出到Excel //从tableview 导出到 EXcle void MainInterfa…...
模版方法模式的理解和实践
在软件开发中,设计模式为我们提供了一套经过验证的解决方案,用于解决常见的设计问题。其中,模版方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并允许子类在不改…...
05-树莓派-交叉编译
交叉编译的概念 交叉编译是什么 来源百度百科: 交叉编译是在一个平台上生成另一个平台上的可执行代码。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。 举例来说,我们常说的x86 Lin…...
杨振宁大学物理视频中黄色的字,c#写程序去掉
先看一下效果:(还有改进的余地) 我的方法是笨方法,也比较刻板。 1,首先想到,把屏幕打印下来。c#提供了这样一个函数: Bitmap bmp new Bitmap(640, 480, PixelFormat.Format32bppArgb); // 创…...
非归档模式下一个或多个数据文件损坏恢复
1. 介绍 有些时侯可能你的库处于非归档的模式下,而你的联机重做日志又currupted,你的数据文件不能完成完全的恢复,这里为大家介绍一个oracle的一个隐藏参数_allow_resetlogs_corruption,让数据库重生。 通过设置隐含参数恢复 alter system …...
k8s 之storageclass使用nfs动态申请PV
文章目录 配置角色权限部署nfs-client-provisioner创建 NFS StorageClass创建 PVC 来动态申请 PV在 Pod 中使用 PVC验证存储是否正确挂载使用 kubectl 和 jq 筛选 PVCwaiting for a volume to be created, either by external provisioner "nfs-diy" or manually cre…...
Spark实训
实训目的: 介绍本实训的基本内容,描述知识目标、,以及本实训的预期效果等。 1、知识目标 (1)了解spark概念、基础知识、spark处理的全周期,了解spark技术是新时代对人才的新要求。 (2)掌握Linux、hadoop、spark、hive集群环境的搭建、HDFS分布文件系统的基础知识与应用…...
Mitel MiCollab 企业协作平台 任意文件读取漏洞复现(CVE-2024-41713)
0x01 产品简介 Mitel MiCollab是加拿大Mitel(敏迪)公司推出的一款企业级协作平台,旨在为企业提供统一、高效、安全的通信与协作解决方案。通过该平台,员工可以在任何时间、任何地点,使用任何设备,实现即时通信、语音通话、视频会议、文件共享等功能,从而提升工作效率和…...
React学习笔记(一)
创建函数写法一: 重点:函数有几种写法 function DemoShow() {return (<div className"App">函数声明</div>); }export default DemoShow;对应js创建函数声明:function sum1(a,b){return ab } 创建函数写法二&#x…...
【H2O2|全栈】MySQL的基本操作(三)
目录 前言 开篇语 准备工作 案例准备 多表查询 笛卡尔积 等值连接 外连接 内连接 自连接 子查询 存在和所有 含于 分页查询 建表语句 结束语 前言 开篇语 本篇继续讲解MySQL的一些基础的操作——数据字段的查询中的多表查询和分页查询,与单表查询…...
SQL按指定字符分割字符串
在SQL中分割字符串通常需要使用特定的函数,因为SQL本身并不像编程语言那样直接支持字符串分割。不同的数据库系统有不同的函数来处理字符串分割。以下是一些常见数据库系统中分割字符串的方法: 1. MySQL 在MySQL中,你可以使用SUBSTRING_IND…...
NAT traversal 原理 | TCP / UDP/ P2P
注:本文为 “NAT traversal ”相关的几篇文章合辑。 未整理去重。 NAT 穿越技术原理 Li_yy123 于 2020-12-08 18:54:26 发布 一、NAT 由来 为了解决全球公有 IPv4 的稀缺,提出了 NAT 技术。NAT 是 Network Address Translation 网络地址转换的缩写。 …...
喜报!极限科技(INFINI Labs)通过国家高新技术企业认定
2024 年 10 月 29 日,国家高新技术企业认定管理工作网公示了北京市认定机构 2024 年认定报备的第一批高新技术企业备案名单,极限数据(北京)科技有限公司 顺利通过本次高新技术企业评审,并获得 国家级“高新技术企业”认…...
在Ubuntu 22.04上搭建Kubernetes集群
Kubernetes 简介 什么是 Kubernetes? Kubernetes(常简称为 K8s)是一个强大的开源平台,用于管理容器化应用程序的部署、扩展和运行。它最初由 Google 设计并捐赠给 Cloud Native Computing Foundation(CNCF࿰…...
【OpenCV】平滑图像
二维卷积(图像滤波) 与一维信号一样,图像也可以通过各种低通滤波器(LPF)、高通滤波器(HPF)等进行过滤。LPF 有助于消除噪音、模糊图像等。HPF 滤波器有助于在图像中找到边缘。 opencv 提供了函数 **cv.filter2D()**&…...
Vue了解
MVVM和MVC区别是什么? MVC : 传统的设计模式。 设计模式: 一套广泛被使用的开发方式 M: model 模型 模型:就是数据的意思 V : view视图 视图:就是页面的意思 C:controlle…...
JS 深拷贝浅拷贝
一、浅拷贝 // 假设有一个JSON对象 let originalObject {name: "Alice",age: 25,interests: ["reading", "coding"] };// 将JSON对象赋值给另一个变量 let copiedObject originalObject;// 修改新变量的属性 copiedObject.age 26;// 输出原始…...
设计模式学习之——单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这个模式的主要目的是控制对象的创建,确保在程序的整个生命周期中,某个类只有一个实例被创…...
Linux Vi/Vim使用 ⑥
掌握 CentOS 7 下的 Vi/Vim 编辑器:从安装到精通 在 CentOS 7 系统的日常运维、编程开发以及各类文本处理场景中,Vi/Vim 编辑器都是不可或缺的得力工具。它以轻量、高效、功能强大著称,虽然初次上手有一定学习门槛,但掌握之后便能…...
【5G】5G技术组件 5G Technology Components
5G的目标设置非常高,不仅在数据速率上要求达到20Gbps,在容量提升上要达到1000倍,还要为诸如大规模物联网(IoT, Internet of Things)和关键通信等新服务提供灵活的平台。这些高目标要求5G网络采用多种新技术…...
Java 学习,字符串比较
Java 字符串比较通常使用 equals() 方法,而不是使用 运算符。因为 运算符,比较的是字符串对象的引用是否相同,而 equals() 方法比较的是字符串的内容是否相同。 使用equals()等方法,比较两个字符串: public class …...
普通算法——二维前缀和
二维前缀和 题目链接:https://www.acwing.com/problem/content/798/ 题目描述: 输入一个 n n n 行 m m m 列的整数矩阵,再输入 q q q 个询问,每个询问包含四个整数 ** x 1 , y 1 , x 2 , y 2 x1,y1,x2,y2 x1,y1,x2,y2 &…...
2024年API接口发展趋势:智能化、自动化引领潮流
随着信息技术的飞速发展,应用程序编程接口(API)已成为现代软件开发的核心组成部分。API作为不同系统之间的桥梁,使得数据、功能和服务能够在各种平台和设备之间无缝流动。在2024年,API接口正经历着一系列显著的变革和发…...
SQL中的通配符:使用LIKE操作符进行模式匹配
在SQL中,LIKE 操作符用于在查询中进行模式匹配。它常用于 WHERE 子句中,以便根据特定模式查找数据。与直接进行精确匹配的 操作符不同,LIKE 允许你使用通配符来对数据进行模糊查询,从而使查询更加灵活和强大。 常见的SQL通配符 …...
数据结构:数组
线性表: 线性表就是数据排成像一条线一样的结构.每个现行表上的数据最多只有前和后两个方向.常见的线性表结构:数组,链表、队列、栈等。 什么是数组: 数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储…...
2022 年“泰迪杯”数据分析技能赛A 题竞赛作品的自动评判
2022 年“泰迪杯”数据分析技能赛A 题竞赛作品的自动评判 完整代码请私聊 博主 一、背景 在各类学科竞赛中,常常要求参赛者提交 Excel 或/和 PDF 格式的竞赛作品。 本赛题以某届数据分析竞赛作品的评阅为背景,要求参赛者根据给定的评分准则和标准答案&a…...
java+ssm+mysql美妆论坛
项目介绍: 使用javassmmysql开发的美妆论坛,系统包含超级管理员,系统管理员、用户角色,功能如下: 用户:主要是前台功能使用,包括注册、登录;查看论坛板块和板块下帖子;…...