Linux的热插拔UDEV机制和守护进程
目录
一、Linux的热插拔UDEV机制
二、守护进程
2.1 守护进程概念和基本特点:
2.2 显示进程信息:
2.3 守护进程和后台进程的区别:
2.4 创建守护进程的步骤和守护进程的特征:
2.4.1 创建守护进程的步骤:
2.4.2 守护进程的特征:
2.5 创建守护进程函数daemon()原型和头文件:
2.6 创建守护进程案例(获取当前时间并写入到日志文件中):
2.7 设置守护进程开机自启动:
三、守护进程应用
3.1 判断某进程是否在运行:
3.2 守护进程不让控制程序退出:
3.3 把相关守护进程设置成开机自启动:
四、UDEV的配置文件(Udev的rules编写)
4.1 UDEV的配置文件:
4.2 UDEV规则的匹配键:
五、自动挂载U盘
5.1 mount手动挂载U盘:
5.2 UDEV自动挂载U盘的配置文件:
5.3 实现自动挂载:
一、Linux的热插拔UDEV机制
Linux 的热插拔机制主要通过 Udev(用户空间设备)来实现。Udev 是 Linux 系统中用于动态管理设备的设备管理器。以下是 Udev 实现热插拔的主要机制:
-  设备事件监测: Udev 不断监听内核发出的事件,以便检测设备的插入和拔出。内核通过 Netlink 通信机制向 Udev 发送设备事件。 
-  规则匹配: 当 Udev 检测到设备事件时,它会根据预定义的规则(规则文件)来匹配事件中的设备信息。规则可以基于设备的各种属性、类型、路径等进行匹配。 
-  规则文件: Udev 的规则文件通常存储在 /etc/udev/rules.d/ 目录下。这些规则文件定义了在特定条件下要执行的操作。规则文件的命名约定通常是 XX-name.rules,其中 XX 是两位数字,用于确定规则文件的加载顺序。 
-  执行动作: 当规则匹配成功时,Udev 将执行相关的动作。动作可以包括创建设备节点、设置环境变量、执行脚本等。例如,可以在设备插入时创建相应的设备节点、加载适当的驱动程序等。 
-  设备节点管理: Udev 负责在 /dev 目录下创建或删除设备节点。这确保了用户和应用程序可以在一个标准位置找到设备节点,而无需关心设备插入的确切时刻。 
-  持久化设备节点: Udev 确保设备节点的持久性,即使设备在重新启动后未连接,也会分配相同的设备节点名称。这有助于确保应用程序可以依赖特定的设备节点。 
总体而言,Udev 通过规则匹配和执行动作的方式,实现了对设备事件的监听和处理,从而支持 Linux 系统的热插拔机制。这使得在系统运行时插入或拔出设备时,系统能够动态地适应这些变化。

-  udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理 /dev目录下的设备文件。通过侦听内核发出来的硬件数据(事件),在用户空间为这个硬件去创建对应代表该硬件的文件,应用程序例如adb就可以通过该文件操作到硬件设备。 
-  udev在用户空间运行,而不在内核空间运行。它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等设备文件通常放在 /dev目录下。使用 udev后,在 /dev目录下就只包含系统中真正存在的设备。 
二、守护进程
守护进程(Daemon Process)是在计算机系统后台运行的一类进程,它们通常在系统启动时启动,不依赖于用户直接操作,一直运行在后台,不受用户登录或注销的影响。守护进程的存在主要是为了执行特定的系统任务或服务,例如服务器、网络服务、定时任务等。
2.1 守护进程概念和基本特点:
-  Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。守护进程的名称通常以d结尾 
-  UDEV守护进程,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。 
基本特点:
-  生存周期长[非必须],一般操作系统启动的时候就启动,关闭的时候关闭。 
-  守护进程和终端无关联,也就是他们没有控制终端,所以当控制终端退出,也不会导致守护进程退出 
-  守护进程是在后台运行,不会占着终端,终端可以执行其他命令 
-  一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程exit退出了,所以它是一个由init继承的孤儿进程 
2.2 显示进程信息:
linux操作系统本身是有很多的守护进程在默默执行,维持着系统的日常活动。大概30-50个
-  ps -efj是一个用于显示进程信息的命令。具体解释如下:
ps -efj		//显示进程信息ps		进程状态命令
-e		显示所有进程,而不仅仅是与终端相关的进程
-f		以全格式显示
-j		以作业格式显示在这个命令中,-ef 是常用组合,用于显示所有进程的详细信息。而 -j 则以作业格式显示,包括作业控制的信息。

输出的各列含义如下:
-  UID (User ID): 进程的用户标识。 
-  PID (Process ID): 进程的唯一标识号。 
-  PPID (Parent Process ID): 父进程的标识号。 
-  PGID (Process Group ID): 进程组的标识号。 
-  SID (Session ID): 会话的标识号。 
-  TTY (Controlling Terminal): 控制终端。 
-  TPGID (Foreground Group ID of the controlling terminal): 控制终端的前台进程组的标识号。 
-  STAT (Process Status): 进程的状态,如 R(运行)、S(睡眠)、Z(僵尸)等。 
-  TIME (Cumulative CPU time): 进程执行的累计 CPU 时间。 
-  COMMAND (Command with all its arguments): 进程的命令及其参数。 
这个命令的输出显示了当前系统上所有进程的详细信息,以及它们的层次结构和作业控制信息。
2.3 守护进程和后台进程的区别:
守护进程和终端不挂钩;后台进程能往终端上输出东西(和终端挂钩);
守护进程关闭终端时不受影响,守护进程不会随着终端的退出而退出;
守护进程(Daemon Process)和后台进程(Background Process)是两个不同的概念,它们有以下区别:
-  启动方式: 
守护进程: 通常由系统启动,独立于控制终端,以在后台运行的方式启动。  后台进程: 可以由用户手动将一个前台进程移至后台,即使它最初是由用户启动的。
-  是否与终端关联: 
守护进程: 通常不与任何控制终端关联,因此它们不受终端关闭的影响。  后台进程: 可以从终端启动,并且可能受终端的影响。
-  执行环境: 
守护进程: 在后台执行,并且通常在系统引导时启动。它们通常在系统运行期间一直存在。  后台进程: 通常是用户在前台启动的进程,后来放到后台执行,可能在终端关闭后继续运行。
-  继承环境: 
守护进程: 通常会脱离终端会话,重新设置文件权限,改变工作目录等,以确保独立于用户终端的环境。  后台进程: 通常继承自其父进程(通常是终端 Shell)的环境。
-  用户交互性: 
守护进程: 通常不与用户进行交互,因为它们不关联于任何终端。  后台进程: 在启动时可能与用户进行交互,但放到后台后通常不再与用户直接交互。
总的来说,守护进程是一种设计用于在系统后台一直运行的进程,而后台进程是一种在终端启动后被放到后台执行的进程。
2.4 创建守护进程的步骤和守护进程的特征:
2.4.1 创建守护进程的步骤:
-  调用 fork函数: 创建一个子进程,父进程退出,子进程继续执行。
-  调用 setsid函数: 创建一个新的会话组,使得子进程成为新的会话组长。
-  修改工作目录: 为了防止卸载文件系统导致守护进程找不到文件,通常需要更改工作目录。 
-  重定向标准输入输出: 将标准输入、输出、错误重定向到适当的文件。 
-  关闭文件描述符: 关闭不需要的文件描述符,避免占用系统资源。 
-  处理信号: 捕获并处理一些信号,如 SIGHUP。
创建和管理守护进程需要谨慎处理,确保进程以安全和可靠的方式在后台运行。
2.4.2 守护进程的特征:
-  后台运行: 守护进程通常在后台运行,不与任何终端关联,不接受用户的直接输入。 
-  脱离终端: 守护进程通常会调用 fork函数创建一个子进程,并使得子进程成为新的会话组长,从而脱离与终端的关联。
-  文件描述符: 守护进程通常会关闭与终端相关的文件描述符,以防止被终端关闭影响进程运行。 
-  重定向标准输入输出: 守护进程通常会将标准输入、输出、错误重定向到 /dev/null或其他适当的文件,以防止输出信息到终端。
-  权限: 守护进程通常以超级用户或其他特定用户的身份运行,以便执行需要特殊权限的任务。 
-  信号处理: 守护进程通常会捕获并处理一些特定的信号,如 SIGHUP,以便在配置文件更改或其他条件下重新加载配置。
-  周期性任务: 守护进程通常执行一些周期性的任务,如定时清理、日志轮转等。 
-  示例: 常见的守护进程包括 sshd(SSH 服务器守护进程)、httpd(Apache HTTP 服务器守护进程)等 
2.5 创建守护进程函数daemon()原型和头文件:
/*Linux下 man daemon查看手册
*/
#include <unistd.h>int daemon(int nochdir, int noclose);int 			函数返回值,函数成功创建守护进程返回0,失败返回-1int nochdir		参数用于指示是否改变守护进程的当前工作目录。如果 nochdir 为非零值,守护进程的当前工作目录将保持不变,为0时表示将当前目录更改至“/”int noclose		参数用于指示是否关闭所有的文件描述符。如果 noclose 为非零值,守护进程将不会关闭标准输入、标准输出和标准错误。为0时表示将标准输入、标准输出、标准错误重定向至“/dev/null”2.6 创建守护进程案例(获取当前时间并写入到日志文件中):
#include <unistd.h>     // 包含unistd.h头文件,提供对POSIX操作系统API的访问,包括各种系统调用
#include <signal.h>     // 包含信号处理函数的头文件
#include <stdlib.h>     // 包含标准库函数的头文件
#include <string.h>     // 包含字符串处理函数的头文件
#include <fcntl.h>      // 包含文件控制选项的头文件
#include <sys/stat.h>   // 包含文件状态信息的头文件
#include <time.h>       // 包含时间处理函数的头文件
#include <stdio.h>      // 包含标准输入输出函数的头文件
#include <stdbool.h>    // 包含布尔类型定义的头文件//C 库函数 char *asctime(const struct tm *timeptr) 返回一个指向字符串的指针,它代表了结构 struct timeptr 的日期和时间。
//C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。timer 的值被分解为 tm 结构,并用本地时区表示。
/*
struct tm {int tm_sec; 秒,范围从 0 到 59int tm_min; 分,范围从 0 到 59int tm_hour; 小时,范围从 0 到 23int tm_mday; 一月中的第几天,范围从 1 到 31int tm_mon; 月份,范围从 0 到 11int tm_year; 自 1900 起的年数int tm_wday; 一周中的第几天,范围从 0 到 6int tm_yday; 一年中的第几天,范围从 0 到 365int tm_isdst; 夏令时
};
*/
static bool flag = true;void handler(int sig)                                                                   //信号处理函数
{printf("I got a signal %d\nI'm quitting.\n", sig);                                  //打印信息flag = false;                                                                   //设置flag为false,退出循环
}int main()
{time_t t;int fd;//创建守护进程if (-1 == daemon(0, 0)){              //创建守护进程,第一个参数为0表示不创建控制终端,第二个参数为0表示不创建进程组     printf("daemon error\n");                                                       //创建守护进程失败  exit(1);                                                                        //退出程序}//设置信号处理函数struct sigaction act;                                                               //信号处理结构act.sa_handler = handler;                                                           //信号处理函数sigemptyset(&act.sa_mask);                                                          //清空信号集act.sa_flags = 0;                                                                   //不设置其他标志if (sigaction(SIGQUIT, &act, NULL)){                                                //设置信号处理函数printf("sigaction error.\n");exit(0);}//进程工作内容while(flag){                                                                        //循环,直到收到信号为止fd = open("/home/orangepi/daemon.log", O_WRONLY | O_CREAT | O_APPEND, 0644);    //打开日志文件if (fd == -1){                                                                  //打开日志文件失败printf("open error\n");                                                     //打印错误信息exit(0);                                                                    //退出程序}t = time(0);                                                                    //获取当前时间char *buf = asctime(localtime(&t));                                             //格式化时间字符串write(fd, buf, strlen(buf));                                                    //写入日志文件close(fd);                                                                      //关闭日志文件sleep(10);                                                                      //睡眠10秒}return 0;
}

可见,时间信息确实不断的追加打印到了这个文件!并且,只要不调用SIGQUIT,哪怕关掉终端也不会结束运行,只有系统关闭才会关闭
主要步骤:
-  使用 daemon函数创建守护进程。
-  设置信号处理函数,处理 SIGQUIT信号。
-  在循环中,打开文件 /home/orangepi/daemon.log,将当前时间写入文件,然后关闭文件,然后休眠10秒。
-  当接收到 SIGQUIT信号时,程序会打印信息并退出。
请确保在运行此程序之前,你有对/home/orangepi/目录的写入权限,并且该目录下没有同名的文件。
2.7 设置守护进程开机自启动:
守护进程一般是开机自启的,实现这一点可以通过“sudo vi /etc/rc.local”,然后添加守护进程的绝对路径来实现:
sudo vi /etc/rc.local
我们重启开发板之后可以看到这个守护进程是开启自启动的:

三、守护进程应用
实现功能:要求抖音语音交互的程序一直保持运行,防止应用程序崩溃意外
3.1 判断某进程是否在运行:
#include <stdio.h>      // 包含标准输入输出库的头文件
#include <string.h>     // 包含字符串操作库的头文件int main()
{FILE *fp;                                               // 定义文件指针char buffer[128] = {'\0'};                              // 定义缓冲区char *cmd = "ps -elf |grep douyinexe |grep -v grep";    // 定义命令//FILE *popen(const char *command, const char *type);fp = popen(cmd, "r");                                   // 使用 popen 函数执行命令并读取结果fgets(buffer, sizeof(buffer), fp);                      // 读取命令的输出if(strstr(buffer, "douyinexe") != NULL){                // 判断是否存在 douyinexe 进程printf("Douyin is running.\n");}else{printf("Douyin is not running.\n");}printf("buffer: %s\n",buffer);                          // 打印命令的输出pclose(fp);                                             // 关闭命令的输出管道return 0;
}

3.2 守护进程不让控制程序退出:
#include <unistd.h>     // 包含unistd.h头文件,提供对POSIX操作系统API的访问,包括各种系统调用
#include <signal.h>     // 包含信号处理函数的头文件
#include <stdlib.h>     // 包含标准库函数的头文件
#include <string.h>     // 包含字符串处理函数的头文件
#include <fcntl.h>      // 包含文件控制选项的头文件
#include <sys/stat.h>   // 包含文件状态信息的头文件
#include <time.h>       // 包含时间处理函数的头文件
#include <stdio.h>      // 包含标准输入输出函数的头文件
#include <stdbool.h>    // 包含布尔类型定义的头文件static bool flag = true;void handler(int sig)                                                                   //信号处理函数
{printf("I got a signal %d\nI'm quitting.\n", sig);                                  //打印信息flag = false;                                                                   //设置flag为false,退出循环
}int existMent()                                                                     //判断是否存在抖音应用程序
{FILE *fp;                                               // 定义文件指针char buffer[128] = {'\0'};                              // 定义缓冲区char *cmd = "ps -elf |grep douyinexe |grep -v grep";    // 定义命令//FILE *popen(const char *command, const char *type);fp = popen(cmd, "r");                                   // 使用 popen 函数执行命令并读取结果fgets(buffer, sizeof(buffer), fp);                      // 读取命令的输出if(strstr(buffer, "douyinexe") != NULL){                // 判断是否存在 douyinexe 进程return 0;                                          // 存在,返回0}else{return -1;                                          // 不存在,返回-1}printf("buffer: %s\n",buffer);                          // 打印命令的输出pclose(fp);                                             // 关闭命令的输出管道
}int main()
{time_t t;int fd;//创建守护进程if (-1 == daemon(0, 0)){               //创建守护进程,第一个参数为0表示不创建控制终端,第二个参数为0表示不创建进程组     printf("daemon error\n");                                                       //创建守护进程失败  exit(1);                                                                        //退出程序}//设置信号处理函数struct sigaction act;                                                               //信号处理结构act.sa_handler = handler;                                                           //信号处理函数sigemptyset(&act.sa_mask);                                                          //清空信号集act.sa_flags = 0;                                                                   //不设置其他标志if (sigaction(SIGQUIT, &act, NULL)){                                                //设置信号处理函数printf("sigaction error.\n");exit(0);}while(flag){                                                                        //循环,直到收到信号为止if(existMent() == -1){system("/home/orangepi/douyin/douyinexe /dev/ttyS5 &");      // 启动抖音应用程序,后台运行                                               sleep(2);                                                    // 等待2秒,确保抖音应用程序启动成功    }}return 0;
}
3.3 把相关守护进程设置成开机自启动:
设置douyinexe进程和守护进程douyindaemon为开启自启动:
sudo vi /etc/rc.local 开机自启动,绝对路径加程序名字

这样开机之后自动的运行刷抖音程序和守护进程程序,不需要用指令来运行程序就可以直接语音刷抖音了。
四、UDEV的配置文件(Udev的rules编写)
4.1 UDEV的配置文件:
-  规则文件是 udev 里最重要的部分,默认是存放在 /etc/udev/rule.d/下。
-  所有的规则文件必须以 " .rules"为后缀名。
下面是一个简单的规则:
KERNEL=="sda", NAME="my_root_disk", MODE="0660"-  KERNEL是匹配键,NAME和MODE是赋值键
-  这条规则的意思是:如果有一个设备的内核名称为 sda,则该条件生效,执行后面的赋值:在/dev下产生一个名为my_root_disk的设备文件,并把设备文件的权限设为 0660。
同时在之前我们的语音刷抖音的项目当中,手机接入香橙派不能识别的解决方案也是在udev的rules文件夹下创建规则文件“ 51-android.rules ”,并写入以下规则:
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"那为什么这个规则要这么写呢?
首先插入手机的USB设备对应的设备文件在/dev/bus/usb/002/006下:

通过指令:udevadm info --attribute-walk --name=/dev/设备名字,可以看到设备的详细信息,此处的设备名字就是006

4.2 UDEV规则的匹配键:
-  ACTION:事件(uevent)的行为,例如:add(添加设备)、remove(删除设备); 
-  KERNEL:内核设备名称,例如:sda,cdrom; 
-  DEVPATH:设备的 devpath 路径; 
-  SUBSYSTEM:设备的子系统名称,例如:sda 的系统为 block; 
-  BUS:设备在 devpath 里的总线名称,例如:usb; 
-  DRIVER:设备在 devpath 的设备驱动名称,例如:ide-cdrom; 
-  ID:设备在 devpath 里的识别号; 
-  SYSFS{filename}:设备的 devpath 路径下,设备的属性文件 "filename" 里的内容; 
-  ENV{key}:环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键; 
-  PROGRAM:调用外部命令; 
-  RESULT:外部命令 PROGRAM 的返回结果。 
五、自动挂载U盘
把我的U盘拿出来,插到香橙派的USB口:

然后执行dmesg指令:

可以看到Linux内核识别到了这个设备,并显示为sda1
5.1 mount手动挂载U盘:
sudo mount /dev/sda1 /mnt/
cd /mnt/
我们可以看到U盘里面的文件和文件夹,但是是乱码的,乱码的原因是因为文件名是中文的,但是这样很麻烦,每次挂载U盘都得执行两个指令才可以挂载,可以使用UDEV来实现自动挂载,我们先把U盘弹出,然后再使用UDEV机制自动挂载U盘:

5.2 UDEV自动挂载U盘的配置文件:
我们首先先执行下面一条指令来查看U盘的信息:
udevadm info --attribute-walk --name=/dev/sda1
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", RUN{program}+="/bin/mkdir /media/%k" ,RUN{program}+="/usr/bin/systemd-mount --no-block --collect $devnode /media/%k"这是一个udev规则,通常用于在插入USB存储设备时自动创建挂载点并挂载设备。这个规则的含义如下:
-  ACTION=="add":规则只在添加设备时触发。
-  SUBSYSTEMS=="usb":设备必须属于USB子系统。
-  SUBSYSTEM=="block": 设备必须是块设备。
-  RUN{program}+="/bin/mkdir /media/%k": 当设备满足规则条件时,运行命令创建 /media/ 目录下以设备名称(%k)命名的目录。
-  RUN{program}+="/usr/bin/systemd-mount --no-block --collect $devnode /media/%k": 运行 systemd-mount 命令,将设备挂载到之前创建的目录。
这个规则的效果是,当插入一个USB块设备时,udev将创建一个以设备名称为名字的目录(例如,如果设备名称是sdb1,那么将创建 /media/sdb1 目录),然后使用systemd-mount挂载设备。
请注意,使用systemd-mount需要系统使用systemd init系统。此外,一般情况下,挂载点应该在/mnt/目录下而不是/media/,因为/media/通常是由文件管理器等工具使用的默认挂载点。
cd /etc/udev/rules.d/
sudo vim my_usbpan.rules
sudo service udev restart
5.3 实现自动挂载:
重新拔插U盘,我们查看media文件夹是否挂载成功:
cd /media
可以看到我们没有输入任何指令,就可以访问U盘里面的文件,实现了自动挂载。另外我们还可以使用tree指令来查看U盘文件:
sudo apt-get install tree		//安装tree指令

此时我们成功自动挂载U盘,使用tree指令来查看U盘的文件,如果我们现在拔掉U盘我们还会发现什么文件都没有了:

相关文章:
 
Linux的热插拔UDEV机制和守护进程
目录 一、Linux的热插拔UDEV机制 二、守护进程 2.1 守护进程概念和基本特点: 2.2 显示进程信息: 2.3 守护进程和后台进程的区别: 2.4 创建守护进程的步骤和守护进程的特征: 2.4.1 创建守护进程的步骤: 2.4.2 守…...
laravel框架基础通识-新手
常用目录及其解析 routes 该目录为路由目录 一般根据api uri可以反向查找对应路由及其controller,目录下的文件名一般和url的第一级对应为了规范,然后根据根据里面具体分组和别名对应拼接对应路由url,后面对应的则是controller,…...
c++ extern 关键字
C中的extern关键字和跨语言互操作 变量的声明与定义 extern关键字用于声明在另一个翻译单元(文件)中定义的变量或函数。通过extern关键字,可以在多个文件中访问全局变量或函数。 变量声明示例 文件:main.cpp #include <io…...
Meta KDD Cup 2024 CRAG: Comphrehensive RAG Benchmark参赛指南(写了一半跑去改大论文了所以没正式参赛)
诸神缄默不语-个人CSDN博文目录 因为比赛过程正好和我毕业答辩的时间段高度重合,所以我……最后其实还是相当于没有成功参赛。 呃反正现在已经咕咕咕了,就把当时写了一半(一小半)的参赛指南发一下吧。 官网:AIcrowd …...
 
系统架构设计师教程 第3章 信息系统基础知识-3.7 企业资源规划(ERP)-解读
系统架构设计师教程 第3章 信息系统基础知识-3.7 企业资源规划(ERP) 3.7.1 企业资源规划的概念3.7.2 企业资源规划的结构3.7.2.1 生产预测3.7.2.2 销售管理(计划)3.7.2.3 经营计划(生产计划大纲)3.7.2.4 …...
 
windows实现自动化按键
1.选择目标窗口 获取窗口句柄 void KeyPresser::selectWindow() {SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);selectedWindowLabel->setText("请点击目标窗口..."); }void CALLBACK …...
 
阿里云 https证书部署
一.申请证书 二.查看状态 查看状态,已签发是完成了申请证书 三.部署 我在nginx服务器上部署 具体操作链接:阿里云文档 修改前 修改后 四.重启ngnix 五.验证是否成功 在浏览器输入域名查看...
 
DX-10A信号继电器 柜内安装,板前接线 约瑟JOSEF
DX-10型闪光信号继电器型号: DX-10A闪光信号继电器; DX-10B闪光信号继电器; DX-10C闪光信号继电器; 用途 DX-10 闪光继电器用于电力系统断路器的位置信号灯不对应闪光,该继电器是为了适应当前推广使用发光二极管节能指示灯而…...
芯片光刻后的晶片多层组合构成的吗
是的,芯片(尤其是集成电路芯片)确实是通过光刻后的晶片多层组合构成的。在芯片制造过程中,光刻是一个至关重要的步骤,用于在硅片(或称为晶片)上刻画出精确的电路图案。然而,一个完整…...
 
OpenGL-ES 学习(7) ---- VBO EBO 和 VAO
目录 VBO(Vertex Buffer Object)EBO(Element Buffer Object)VAO(Vertex Array Object) VBO(Vertex Buffer Object) EBO(Element Buffer Object) VBO(Vertex Buffer Object) 实际是指顶点缓冲器对象 在 opengl-es 2.0 的编程中,用于绘制图元的顶点数据是从 CPU 传…...
github如何实现和gitlab的同步
要实现 GitHub 和 GitLab 之间的同步,你可以使用以下几种方法。这里介绍两种常用的方法:使用 GitLab CI/CD 和使用镜像仓库。 方法1:使用 GitLab CI/CD 通过 GitLab CI/CD,可以在每次推送到 GitLab 时自动同步到 GitHub。以下是…...
 
内网隧道——隧道技术基础
文章目录 一、正向连接与反向连接1.1 正向连接1.2 反向连接 二、端口转发三、端口映射四、端口复用五、代理和隧道的区别六、常见隧道穿透分类 环境: kali:192.168.92.6,MSF v6.3.25 win7:192.168.92.7 一、正向连接与反向连接 1…...
 
NAS新品“翻车”后,绿联科技要上市了
在消费电子市场回暖的东风中,又一消费电子知名企业登陆A股。 近日,深圳市绿联科技股份有限公司(下称“绿联科技”)开启申购,将在创业板上市。本次上市,绿联科技的发行价为21.21元/股,发行数量为…...
kafka-client如何打印连接日志
在Kafka客户端中打印连接日志,通常涉及配置日志框架来捕获和输出Kafka客户端在建立连接过程中的相关信息。由于Kafka客户端使用SLF4J(Simple Logging Facade for Java)作为日志门面,实际的日志实现(如Log4j2、Logback等…...
 
1、springboot3 vue3开发平台-后端-项目构建
文章目录 1. 创建项目1.1 前置环境条件1.2 项目创建 2. 模块配置2.1 父工程配置概述2.2 配置启动模块2.3 父工程相关依赖管理 1. 创建项目 1.1 前置环境条件 idea2023, jdk17 1.2 项目创建 创建父工程并删除不需要的文件目录: 右键父工程依次创建其他模块 最…...
 
修改了mybatis的xml中的sql不重启服务器如何动态加载更新
目录 一、背景 二、注意 三、代码 四、使用示例 五、其他参考博客 一、背景 开发一个报表功能,好几百行sql,每次修改完想自测下都要重启服务器,启动一次服务器就要3分钟,重启10次就要半小时,耗不起时间呀。于是在…...
 
Intel和AMD用户再等等!微软确认Win11 24H2年底前登陆
微软近日确认,Windows 11 24H2版本将于2024年底前正式登陆使用英特尔和AMD处理器的PC。 根据微软介绍,Windows 11 24H2将作为传统功能更新,将在今年晚些时候提供给所有设备。 此前,微软已向搭载骁龙X Plus和X Elite系列处理器的Co…...
 
Web开发:图片九宫格与非九宫格动态切换效果(HTML、CSS、JavaScript)
目录 一、业务需求 二、实现思路 三、实现过程 1、基础页面 2、图片大小调整 3、图片位置调整 4、鼠标控制切换 5、添加过渡 四、完整代码 一、业务需求 默认显示基础图片; 当鼠标移入,使用九宫格效果展示图片; 当鼠标离开&#…...
 
价格较低,功能最强?OpenAI 推出 GPT-4o mini,一个更小、更便宜的人工智能模型
OpenAI美东时间周四推出“GPT-4o mini”,入局“小而精”AI模型竞争,称这款新模型是“功能最强、成本偏低的模型”,计划今后整合图像、视频、音频到这个模型中。 OpenAI表示,GPT-4o mini 相较于 OpenAI 目前最先进的 AI 模型更加便…...
 
【学习笔记】无人机系统(UAS)的连接、识别和跟踪(八)-无人机探测与避让(DAA)机制
目录 引言 5.6 探测与避让(DAA)机制 5.6.1 基于PC5的探测与避让(DAA)机制 引言 3GPP TS 23.256 技术规范,主要定义了3GPP系统对无人机(UAV)的连接性、身份识别、跟踪及A2X(Airc…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
 
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
 
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
 
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
 
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
