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

Linux高级编程_29_信号

文章目录

  • 进程间通讯 - 信号
    • 信号
      • 完整的信号周期
      • 信号的编号
      • 信号的产生
      • 发送信号
        • 1 kill 函数(他杀)
          • 作用:
          • 语法:
            • 示例:
        • 2 raise函数(自杀)
          • 作用:
          • 示例:
        • 3 abort函数(自杀)
          • 作用:
          • 语法:
            • 示例:
        • 4 alarm函数(自杀)
          • 只能延迟执行
          • 作用:
          • 语法:
            • 示例:
        • 5 settimer函数(定时器)[扩展]
          • 延迟重复执行
        • 6 pause函数
    • 自定义信号处理
      • 1 signal
        • 作用:
        • 语法:
      • 2 sigaction
        • 作用:
        • 语法:
          • struct sigaction:结构体
      • 可重入函数
        • 概述:
        • 注意:
      • 信号集
        • 概述
      • 自定义信号集函数
      • 信号阻塞集
        • 概述
        • sigprocmask函数
          • 作用:
          • 语法:

进程间通讯 - 信号

中文名:进程间通讯

英文名:IPC

英文全称:Inter Processes Communication

作用:进程间互相传递信息

数据传输:一个进程需要将它的数据发送给另一个进程。
资源共享:多个进程之柯共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。

分类:

  • 信号
  • 管道
  • 文件共享
  • 网络【socket】

发展史:

  • 最初的UNIX进程间通信
  • SYSTEMV 进程间通信
  • POSIX 进程间通信(PosIX:PortableOperatingSysteminterface 可移植操作系统接口)
  • Socket进程间通信
  • Linux把优势都继承了下来并形成了自己的IPC

Linux进程间通信

在这里插入图片描述

信号

信号是 Linux 进程间通信的最古老的方式

特点:

  • 简单
  • 不能携带大量信息
  • 满足某个特设条件才发出。【也就是不管发 管收】

注意:

  • 1 信号是一种异步通信方式
  • 2 信号是软件中断,它是在软件层次上对中断机制的一种模拟。
  • 3 信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。
  • 4 进程不必等待信号的到达,进程也不知道信号什么时候到达。
  • 5 信号可以直接进行用户空间进程和内核空间进程的交互,内核进程可以利用它来通知用户空间进程发生哪些系统事件

名词解释

  • 同步:事件、操作或进程是有序的,一个操作必须在另一个操作完成后开始执行
  • 异步:事件、操作或进程是独立的,可以在不等待其他操作完成的情况下开始执行
  • 中断机制:是现代计算机系统中的基本机制之一,完成了对计算机各个事件(如时钟、键盘等)响应工作
  • 硬件中断:是由硬件设备触发的中断,如时钟中断、串口接收中断、外部中断等。

完整的信号周期

  • 发送信号
  • 接收信号
  • 信号的处理(默认、忽略、自定义)
  • 信息的注销

信号的编号

注意:信号不能自定义每个信号的名字都以字符 SIG 开头。
每个信号和一个数字编码相对应,在头文件 signum.h 中,这些信号都被定义为正整数。信号名定义路径:/usr/include/asm-generic/signal.h在Linux下,要想查看这些信号和编码的对应关系,可使用命令:kill -l不存在编号为0的信号。1-31号信号称之为常规信号(也叫普通信号,标准信号)34-64号信号称之为实时信号(自定义信号)通过man 7 signal查看信号帮助文档注意:9) SIGKILL 和 19) SIGSTOP 信号,不允许忽略和捕捉,只能执行默认动作。(重要)SIGQUIT信号由:Ctrl + \触发SIGINT信号由:ctrl+c触发

在这里插入图片描述

在这里插入图片描述

注意:信号不能自定义

  • kill -l
  • man 7 signal
>通过  kill -l 查看每个信号的名字都以字符 SIG 开头。每个信号和一个数字编码相对应,在头文件ignal.h中,这些信号都被定义为正整数。信号名定义路径:/usr/include/asm-generic/signal.h	> 不存在编号为0的信号。1-31号信号称之为常规信号(也叫普通信号,标准信号)34-64号信号称之为实时信号(自定义信号)
通过man	7	signal	查看信号帮助文档  
注意:9)SIGKILL和19)SIGSTOP信号,不允许忽略和捕捉,只能执行默认动作。(重要)
SIGQUIT 信号由:Ctr]+\触发
SIGINT 	信号由:ctrl +c触发

信号的产生

	1, 当用户按某些终端键时,将产生信号。 终端上按“Ctrl+c”组合键通常产生中断信号 SIGINT 终端上按“Ctrl+\”键通常产生中断信号 SIGQUIT 终端上按“Ctrl+z”键通常产生中断信号 SIGSTOP 等。2,硬件异常将产生信号。 除数为0,无效的内存访问等。这些情况通常由硬件检测到,并通知内核,然后内核产生适当的信号发送给相应的进程。3,软件异常将产生信号。 当检测到某种软件条件已发生(如:定时器 alarm),并将其通知有关进程时,产生信号。4,调用系统函数(如:kill、raise、abort)将发送信号。
注意:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户。5,运行 kill/killall 命令将发送信号。 此程序实际上是使用 kill 函数来发送信号。也常用此命令终止一个失控的后台进程。

发送信号

1 kill 函数(他杀)
作用:

给指定进程发送指定信号(不一定杀死),他杀

语法:
>	头文件:#include <sys/types.h>#include <signal.h>
函数int kill(pid_t pid, int sig);
参数:pid:取值有4种情况:pid〉O:将信号传送给进程 ID 为 pid 的进程。pid=0:将信号传送给当前进程所在的进程组中的所有进程。pid=-1:将信号传送给系统内所有的进程。pid〈-1:将信号传给指定进程组的所有进程。这个进程组号等于pid的绝对值。				sig:信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令ki1]-1("]”为字母)进行相应查看。不推荐直接使用数字,应使用宏名,因为不同操作系统信号编号可能不同,但名称一致。> 返回值:成功:0失败:-1
示例:
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{int pid = fork();if (pid == 0){printf("子进程开始\n");while (1);printf("子进程end\n");}else if (pid > 0){printf("当前进程开始\n");printf("3秒后发送信号给子进程\n");sleep(3);// 给子进程发送 SIGINT 信号kill(pid, SIGINT);printf("当前进程已经发送了信号\n");int id = wait(NULL);printf("进程%d被回收了\n",id);}return 0;
}

在这里插入图片描述

2 raise函数(自杀)

#include <signal.h>

作用:

自己给自己发信号

语法:

函数int raise(int sig);
参数:sig:信号编号
返回值:成功:0失败:非 0
注意:该函数等价与kill(getpid(),sig);
示例:
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{printf("当前进程开始 \n");//发送停止信号raise(SIGSTOP);while (1)printf("当前进程结束 \n");return 0;
}

在这里插入图片描述

3 abort函数(自杀)
作用:

给自己发送异常终止信号 6) SIGABRT,并产生 core 文件,等价于 kill(getpid(), SIGABRT)

core文件(了解)

core就是内核
core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种
函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多
的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程
序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。
语法:
所需头#include <stdlib.h>
函数void abort(void);
注意:1,使用abort函数结束进程,进程结束前会刷新缓冲区并关闭所有的文件描述符(0/1/22,即使 SIGABRT 信号被加入阻塞集,一旦进程调用了 abort 函数,进程也还是会被终止
示例:
#include <stdio.h>
#include <stdlib.h>
//  abort() 给自己发送异常终止信号
int main(int argc, char const *argv[])
{printf("当前进程开始 \n");abort();while (1)printf("当前进程结束 \n");return 0;
}
4 alarm函数(自杀)
只能延迟执行

#include <unistd.h>

作用:
>
设置定时器(闹钟)。在指定时间后(单位秒),内核会给当前进程发送 14)SIGALRM 信号。进程收到该信号,默认动作终止。每个进程都有且只有唯一的一个定时器。取消定时器 alarm(0),返回旧闹钟余下秒数。
语法:
函数unsigned int alarm(unsigned int seconds);
参数:seconds:时间,单位秒
返回值:若以前没有设置过定时器,或设置的定时器已超时,返回0;否则返回定时器剩余的秒数,并重新设定定时器

注意:

定时,与进程状态无关(即自然定时法)!就绪、运行、挂起(阻塞、暂停)、终止、僵尸……无论进程处于何种状态,alarm 都计时不阻塞当前进程
示例:
#include <stdio.h>
#include <unistd.h>
//    alarm函数(自杀)
int main(int argc, char const *argv[])
{printf("当前进程开始 \n");alarm(5);  //每过五秒就自杀 不阻塞进程 也就不妨碍下面进程的执行int i = 0;while (1){sleep(1);i++;printf("已经过去了%d秒\n", i);}printf("当前进程结束 \n");return 0;
}

在这里插入图片描述

示例2: 设置了 0 就是取消定时

因为死循环 就会一直执行 不会发出杀死进程的信号

#include <stdio.h>
#include <unistd.h>
//    alarm函数(自杀)
int main(int argc, char const *argv[])
{printf("当前进程开始 \n");alarm(5);  //每过五秒就自杀 不阻塞进程 也就不妨碍下面进程的执行alarm(0); // 0 代表取消int i = 0;while (1){sleep(1);i++;printf("已经过去了%d秒\n", i);}printf("当前进程结束 \n");return 0;
}

在这里插入图片描述

5 settimer函数(定时器)[扩展]
延迟重复执行

等价 kill+sleep 【开发实际 会选用 kill + sleep】

settimer 开发有延迟重复执行就用

alarm 开发需要延迟执行就用它

但是 kill + sleep 其实就够用

作用: 设置定时器(闹钟)。 可代替 alarm 函数。精度微秒 us,可以实现周期定时。

语法:

> 所需头文件#include <sys/time.h>
> 函数
int setitimer(int which, const struct itimerval *new_value, structitimerval *old_value);>参数:which:指定定时器类型,可以是以下三个值之一:a) 自然定时:ITIMER_REAL → 14)SIGALRM 计算自然时间b) 虚拟空间计时(用户空间):ITIMER_VIRTUAL → 26)SIGVTALRM 只计算进程占用 cpu 的时间c) 运行时计时(用户+内核):ITIMER_PROF → 27)SIGPROF 计算占用 cpu及执行系统调用的时间new_value:一个指向struct itimerval结构体的指针,用于指定新的定时器值(启动时间和间隔时间)。old_value:一个指向struct itimerval结构体的指针,用于获取旧的定时器值,即之前设置的定时器值。如果不需要获取旧的定时器值,则可以传入NULL>注意:设置的value一定要全部设置值,因为结构体成员变量默认值为随机数

在这里插入图片描述

struct itimerval 结构体

struct itimerval 
{struct timerval it_interval; // 间隔时间struct timerval it_value; // 延迟时间
};

struct timerval结果体

struct timeval
{long tv_sec; // 秒long tv_usec; // 微秒
};

示例

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
extern void fun01();
int main(int argc, char const *argv[])
{
//注意  因为 是结构体 所以成员变量初始值 是随机数  使用时 全部初始化 signal(SIGALRM,fun01);struct itimerval val;val.it_value.tv_sec=3;    // 设置 延迟时间为3sval.it_value.tv_usec=0;val.it_interval.tv_sec=1.5; // 设置 间隔时间为1sval.it_interval.tv_usec=0;setitimer(ITIMER_REAL,&val,NULL);while(1);return 0;
}
void fun01()
{printf("收到信号\n");// _exit(0); 
}

在这里插入图片描述

6 pause函数

作用:捕捉信号,会阻塞当前进程

语法: #include <unistd.h>

	int pause(void);
返回值:直到捕获到信号pause返回 -1 并且errno 被设置为 EINTR

示例:

#include <stdio.h>
#include <unistd.h>
// pause()函数  会阻塞进程
int main(int argc, char const *argv[])
{printf("开始咯\n");pause();printf("开始咯\n");return 0;
}

在这里插入图片描述

自定义信号处理

信号处理:

  • 默认 SIG_DEF
  • 忽略 SIG_IGN
  • 自定义 函数名

注意:

SIGSTOP 与 SIGKILL 这两个信号 不能或略 不能自定义 只能默认

1 signal

作用:

​ 可以用于进程间通讯

语法:

# include <signal.h>

函数:sighandler_t signal(int signum, sighandler_t handler);
参数:signum:信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过
命令 kill - l("l" 为字母)进行相应查看。>handler : 取值有 3 种情况:SIG_IGN:忽略该信号SIG_DFL:执行系统默认动作信号处理函数名:自定义信号处理函数//定义的一个函数指针typedef void(*sighandler_t)(int);
返回值:成功:第一次返回 NULL,下一次返回此信号上一次注册的信号处理函数的地址。如果需要使用此返回值,必须在前面先声明此函数指针的类型。
失败:返回 SIG_ERR
  • 通过 kill -l 查看

    • 每个信号的名字都以字符 SIG 开头。
    • 每个信号和一个数字编码相对应,在头文件ignal.h中,这些信号都被定义为正整数。
    • 信号名定义路径:/usr/include/asm-generic/signal.h
  • 不存在编号为0的信号。

    • 1-31号信号称之为常规信号(也叫普通信号,标准信号)
    • 34-64号信号称之为实时信号(自定义信号)

在这里插入图片描述

示例1:

注意: sigCode 返回的是 信号编号

#include <stdio.h>
#include <signal.h>
void fun(int sigCode)
{printf("sigCode = %d\n", sigCode);printf("sigCode 是用来获取信号编号的");printf("你好,这是只有按下 CTRL+c 后显示的函数内容\n");
}
int main(int argc, char const *argv[])
{// SIGINT  键盘ctrl+c 就触发信号// signal(SIGINT, SIG_DFL); // 这是默认处理   也就是停止进程// signal(SIGINT,SIG_IGN); //SIG_IGN 忽略// 绑定信号//  当按下 CTRL + c 就去执行函数  funsignal(SIGINT, fun);while (1);return 0;
}

在这里插入图片描述

示例2:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
int tag = 1;
void fun()
{tag = 0;
}
void fun02()
{printf("子进程结束了\n");
}
int main(int argc, char const *argv[])
{int pid = fork();if (pid == 0){signal(SIGUSR1, fun);for (int i = 0; i < 100 && tag; i++){sleep(1);printf("已下载:%d%%\n", i + 1);}printf("结束下载\n");kill(getpgrp(), SIGUSR2);}else if (pid > 0){signal(SIGUSR2, fun02);printf("5秒后停止下载\n");sleep(5);kill(pid, SIGUSR1);wait(NULL);}return 0;
}

2 sigaction

作用:

​ 检查或修改指定信号的设置(或同时执行这两种操作)。

语法:

#include <signal.h>

> 函数:int sigaction(int signum, const struct sigaction *act, struct sigaction* oldact);
> 参数:signum:要操作的信号。act: 要设置的对信号的新处理方式(传入参数)。oldact:原来对信号的处理方式(传出参数)。
> 注意:如果act指针非空,则要改变指定信号的处理方式(设置),如果oldact指针非空,则系统将此前指定信号的处理方式存入oldact。
> 返回值:成功:0失败:-1
struct sigaction:结构体
struct sigaction
{void (*sa_handler)(int);                           // 旧的信号处理函数指针 void (*sa_sigaction)(int, siginfo_t *, void *); // 新的信号处理函数指针sigset_t sa_mask;          // 信号阻塞集int sa_flags;              // 信号处理的方式void (*sa_restorer)(void); // 已弃用
};
/*1,sa_handler,sa_sigaction:信号处理函数指针,和signal()里的函数指针用法一样,应根据情况给 sa_sigaction、sa_handler 两者之一赋值,其取值如下:a SIGIGN:忽略该信号b SIGDFL:执行系统默认动作c 处理函数名:自定义信号处理函数2,sa_mask:信号阻塞集,在信号处理函数执行过程中,临时屏蔽指定的信号。3,sa_flags:用于指定信号处理的行为,通常设置为 0,表使用默认属性。它可以是以下值的“按位或”组合:SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃)SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD信号。SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。SA_RESETHAND:信号处理之后重新设置为默认的处理方式SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理
函数void(*sa_sigaction)(int signum, siginfo_t *info, void *context);
参数说明:signum:信号的编号。info:记录信号发送进程信息的结构体。context:可以赋给指向ucontext_t类型的一个对象的指针,以引用在传递信号时被中断的接收进程或线程的上下文。
*/
#include <stdio.h>
#include <signal.h>
void fun()
{printf("已处理\n");
}
int main(int argc, char const *argv[])
{struct sigaction mys;mys.sa_handler = fun;sigaction(SIGINT, &mys, NULL);while (1);return 0;
}

可重入函数

概述:
一种特殊的函数
多个进程执行同一个函数,多个进程之间互不干扰,该函数为可重入函数
注意:
1、不使用或返回 静态的数据、全局变量(除非用信号量互斥)。
2、不调用动态内存分配、释放的函数。
3、不调用任何不可重入的函数(如标准 I/O 函数)

系统提供的可重入函数

在这里插入图片描述

信号集

概述
> 在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未决信号集”。 这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对其进行位操作。而需自定义另外一个集合,借助信号集操作函数来对 PCB 中的这两个信号集进行修改> 信号阻塞集:将某些信号加入 集合,对他们设置屏蔽,当屏蔽 x 信号后,再收到该信号,该信号的处理将暂缓。> 未决信号集:未被处理的信号集合。

在这里插入图片描述

自定义信号集函数

所需头文件
#include <signal.h>

函数int sigemptyset(sigset_t *set); //将 set 集合置空int sigfillset(sigset_t *set)//将所有信号加入 set 集合int sigaddset(sigset_t *set, int signo); //将 signo 信号加入到 set合int sigdelset(sigset_t *set, int signo); //从 set 集合中移除 signo信号int sigismember(const sigset_t *set, int signo); //判断信号是否存在于集合中

信号阻塞集

概述
>	信号阻塞集也称信号屏蔽集、信号掩码。
> 	每个进程都有一个阻塞集,创建子进程时子进程将继承父进程的阻塞集。信号阻塞集用来描述哪些信号递送到该进程的时候被阻塞(在信号发生时记住它,直到进程准备好时再将信号通知进程)。 所谓阻塞并不是禁止传送信号, 而是暂缓信号的传送。若将被阻塞的信号从信号阻塞集中删除,且对应的信号在被阻塞时发生了,进程将会收到相应的信号。> 	我们可以通过 sigprocmask() 修改当前的信号阻塞集来改变信号的阻塞情况。
sigprocmask函数
作用:

检查或修改信号阻塞集,根据 how 指定的方法对进程的阻塞集合进行修改,新的信号阻塞集由 set 指定,而原先的信号阻

塞集合由 oldset 保存。

语法:

所需头文件

#include <signal.h>

函数int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数how:信号阻塞集合的修改方法,3种情况:SIG_BLOCK:添加向信号阻塞集合中添加set信号集,新的信号掩码是set和旧信号掩码的并集.相当于mask=mask|set。SIG_UNBLOCK:删除从信号阻塞集合中删除set信号集,从当前信号掩码中去除set中的信号.相当于mask=mask&~set。SIG_SETMASK:替换	将信号阻塞集合设为set信号集,相当于原来信号阻塞集的内容清空,然后按照set中的信号重新设置信号阻塞集。相当于mask=set。
>	set:要操作的信号集地址。若set为NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到oldset中
>	oldset:保存原先信号阻塞集地址
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
//   进程的加锁  与解锁
void fun()
{printf("已处理\n");
}
int main(int argc, char const *argv[])
{signal(SIGINT, fun);sigset_t set;sigemptyset(&set);sigaddset(&set, SIGINT);sigprocmask(SIG_BLOCK, &set, NULL);  //设置阻塞printf("3秒后移除对SIGINT的阻塞\n");sleep(3);sigprocmask(SIG_UNBLOCK, &set, NULL);   //解除阻塞while (1);return 0;
}
	SIG_BLOCK:添加向信号阻塞集合中添加set信号集,新的信号掩码是set和旧信号掩码的并集.相当于mask=mask|set。SIG_UNBLOCK:删除从信号阻塞集合中删除set信号集,从当前信号掩码中去除set中的信号.相当于mask=mask&~set。SIG_SETMASK:替换	将信号阻塞集合设为set信号集,相当于原来信号阻塞集的内容清空,然后按照set中的信号重新设置信号阻塞集。相当于mask=set。
set:要操作的信号集地址。若set为NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到oldset中
oldset:保存原先信号阻塞集地址
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
//   进程的加锁  与解锁
void fun()
{printf("已处理\n");
}
int main(int argc, char const *argv[])
{signal(SIGINT, fun);sigset_t set;sigemptyset(&set);sigaddset(&set, SIGINT);sigprocmask(SIG_BLOCK, &set, NULL);  //设置阻塞printf("3秒后移除对SIGINT的阻塞\n");sleep(3);sigprocmask(SIG_UNBLOCK, &set, NULL);   //解除阻塞while (1);return 0;
}

在这里插入图片描述

相关文章:

Linux高级编程_29_信号

文章目录 进程间通讯 - 信号信号完整的信号周期信号的编号信号的产生发送信号1 kill 函数(他杀)作用&#xff1a;语法&#xff1a;示例&#xff1a; 2 raise函数(自杀)作用&#xff1a;示例&#xff1a; 3 abort函数(自杀)作用&#xff1a;语法&#xff1a;示例&#xff1a; 4 …...

uniapp修改uni-ui组件样式(对微信小程序/H5有效,vue3)

寻找要修改的样式 使用开发者工具找到具体要修改的class类名 修改 <style lang"scss">//.nav为上一级的class.nav::v-deep .uni-navbar--border {border-bottom-style: none !important;} </style>完整代码 <template><view><uni-na…...

Python 封装 socket 为 [TCP/UDP/MULTICAST] 服务端

在新线程中创建 TCP/UDP/MULTICAST 协议的服务端套接字&#xff0c;接收客户端的连接请求或数据&#xff0c;并调用 on_recv 回调函数处理数据。 #!/usr/bin/env python # -*- coding: utf-8 -*- import socket import threading import multiprocessingclass ServerSocket:de…...

c++ STL库 unordered_map

#include <iostream #include <string #include <unordered_map int main() { // 创建一个 unordered_map std::unordered_map<std::string, int> wordCount; // 插入元素 wordCount["apple"] 1; wordCount["banana"] 2;// 使用 insert…...

【接口测试】任务1:登录接口

需要技能竞赛软件测试资料的同学们可s聊我&#xff0c;详细了解 任务实现要求 根据系统管理员—登录—接口API文档&#xff0c;编写接口测试用例&#xff0c;分别使用PostMan及JMeter进行接口测试&#xff0c;需要检查系统接口是否能正常工作&#xff0c;返回值是否正确&#…...

二、Spring Boot集成Spring Security之实现原理

Spring Boot集成Spring Security之实现原理 一、Spring Security实现原理概要介绍二、使用WebSecurityConfiguration向Spring容器中注册FilterChainProxy类型的对象springSecurityFilterChain1、未配置securityFilterChain过滤器链时使用默认配置用于生成默认securityFilterCha…...

基于深度学习的点云处理模型PointNet++学习记录

前面我们已经学习了Open3D&#xff0c;并掌握了其相关应用&#xff0c;但我们也发现对于一些点云分割任务&#xff0c;我们采用聚类等方法的效果似乎并不理想&#xff0c;这时&#xff0c;我们可以想到在深度学习领域是否有相关的算法呢&#xff0c;今天&#xff0c;我们便来学…...

Javascript Object.assgin()详解以及深浅拷贝

Object.assign() 方法是 JavaScript 中用于将所有可枚举属性的值从一个或多个源对象复制到目标对象的方法。它将返回目标对象。这是一种浅拷贝&#xff0c;也就是说&#xff0c;如果源对象中的属性是一个对象或数组&#xff0c;那么这个属性的引用将被复制&#xff0c;而不是对…...

Redis篇(应用案例 - UV统计)(持续更新迭代)

目录 一、HyperLogLog 二、测试百万数据的统计 一、HyperLogLog 首先我们搞懂两个概念&#xff1a; UV&#xff1a;全称Unique Visitor&#xff0c;也叫独立访客量&#xff0c;是指通过互联网访问、浏览这个网页的自然人。 1天内同一个用户多次访问该网站&#xff0c;只记录…...

解锁微信小程序新技能:ECharts动态折线图搭配WebSocket,数据刷新快人一步!

在微信小程序中&#xff0c;数据可视化展示越来越受到开发者的重视。本文将为您介绍如何在微信小程序中使用ECharts绘制折线图&#xff0c;并通过WebSocket实现实时更新图表数据。 一、准备工作 创建微信小程序项目 首先&#xff0c;我们需要创建一个微信小程序项目。如果您已…...

上交所服务器崩溃:金融交易背后的技术隐患暴露杭州BGP高防服务器43.228.71.X

一、上交所宕机事件始末 2024 年 9 月 27 日&#xff0c;上交所交易系统突发崩溃&#xff0c;这一事件犹如一颗巨石投入平静的湖面&#xff0c;引起了轩然大波。当天上午&#xff0c;众多投资者反馈券商交易出现延迟问题&#xff0c;随后上交所发布了《关于股票竞价交易出现异常…...

P4、P4D、HelixSwarm 各种技术问题咨询

多年大型项目P4仓库运维经验&#xff0c;为你解决各种部署以及标准工业化流程问题。 Perforce 官网SDPHelixCore GuideHelixSwarm GuideHelixSwarm Download...

Linux 应用层协议HTTP

文章目录 一、初始HTTP协议二、URL格式网络中怎么通过URL进行定位资源呢&#xff1f;编码和解码 三、HTTP的请求格式和响应格式HTTP的请求格式HTTP的响应格式HTTP的请求方法GET方法POST方法GET Vs PostHTTP的封装和分用文件流操作浏览器获得一个完整的网页流程 HTTP的状态码对3…...

Python和C++混淆矩阵地理学医学物理学视觉语言模型和算法模型评估工具

&#x1f3af;要点 优化损失函数评估指标海岸线检测算法评估遥感视觉表征和文本增强乳腺癌预测模型算法液体中闪烁光和切伦科夫光分离多标签分类任务性能评估有向无环图、多路径标记和非强制叶节点预测二元分类评估特征归因可信性评估马修斯相关系数对比其他准确度 Python桑…...

HTTP 协议的基本格式和 fiddler 的用法

HTTP协议格式 HTTP是⼀个⽂本格式的协议.可以通过Chrome开发者⼯具或者Fiddler抓包,分析HTTP请求/响应的细节. 抓包工具的使用 以Fiddler为例. • 左侧窗⼝显⽰了所有的HTTP请求/响应,可以选中某个请求查看详情. • 右侧上⽅显⽰了HTTP请求的报⽂内容.(切换到Raw标签⻚可以看…...

【计算机网络】详解UDP协议格式特点缓冲区

一、UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度&#xff1b;如果16位UDP检验和出错&#xff0c;报文会被直接丢弃。 1.1、检验和出错的几种常见情况 数据传输过程中的比特翻转&#xff1a;在数据传输过程中&#xff0c;由于物理介质或网络设…...

网络安全cybersecurity的几个新领域

一、电力安全 同学们&#xff0c;今天我们来讨论一下为什么网络安全&#xff08;Cybersecurity&#xff09;和电力系统&#xff08;Power Systems&#xff09;这两个看似不同的领域会有交集。其实&#xff0c;这两个领域之间的联系非常紧密。以下我将从多个角度进行解释&#…...

android 原生加载pdf

implementation("androidx.pdf:pdf-viewer-fragment:1.0.0-alpha02") pdf加载链接...

MAE(平均绝对误差)和std(标准差)计算中需要注意的问题

一、MAE&#xff08;平均绝对误差&#xff09; 计算公式&#xff1a; yi​ 是第i个实际值y^​i​ 是第i个预测值 计算方法&#xff1a; MAE就是求实际值与预测值之间的误差&#xff0c;需要给出预测值和原始的实际值 二、std&#xff08;标准差&#xff09; 计算公式&#x…...

03实战篇:把握667分析题的阅读材料、题目

本节你将学习到&#xff1a; 如何快速识别阅读材料的有效信息如何把握题目的作答方向 在正式进入具体的实战之前&#xff0c;我想先来讲一讲如何利用给定阅读材料、如何分析题目来确保不偏题等基础性知识。 高效利用给定阅读材料的方法 根据博主的实战经验来看&#xff0c;阅…...

C++系列-多态

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 多态 多态就是不同类型的对象&#xff0c;去做同一个行为&#xff0c;但是产生的结果是不同的。 比如说&#xff1a; 都是动物叫声&#xff0c;猫是喵喵&#xff0c;狗是汪汪&am…...

基于C++和Python的进程线程CPU使用率监控工具

文章目录 0. 概述1. 数据可视化示例2. 设计思路2.1 系统架构2.2 设计优势 3. 流程图3.1 C录制程序3.2 Python解析脚本 4. 数据结构说明4.1 CpuUsageData 结构体 5. C录制代码解析5.1 主要模块5.2 关键函数5.2.1 CpuUsageMonitor::Run()5.2.2 CpuUsageMonitor::ComputeCpuUsage(…...

fish-speech语音大模型本地部署

文章目录 fish-speech模型下载编译部署 小结 fish-speech模型 先说下fish-speech模型吧&#xff0c;可以先看下官网。如下&#xff1a; 这就是一个模型&#xff0c;可以根据一个样例声音&#xff0c;构建出自己需要的声音。其实&#xff0c;这个还是有很多用途的&#xff1b;…...

如何写出更牛的验证激励

前言 芯片验证是为了发现芯片中的错误而执行的过程&#xff0c;它是一个破坏性的过程。完备的验证激励可以更有效地发现芯片错误&#xff0c;进而缩短验证周期。合格的验证激励必须能产生所有可能的验证场景(完备性)&#xff0c;包括合法和非法的场景&#xff0c;并保持最大的…...

EasyCVR视频汇聚平台:解锁视频监控核心功能,打造高效安全监管体系

随着科技的飞速发展&#xff0c;视频监控技术已成为现代社会安全、企业管理、智慧城市构建等领域不可或缺的一部分。EasyCVR视频汇聚平台作为一款高性能的视频综合管理平台&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;在构建智慧安防/视频监控系统中展现出了…...

面对大文件(300G以上)如何加速上传速度

解题思路 采用分片上传&#xff0c;同时每个分片多线程上传可以加速上传速度&#xff0c;上传速度提升10倍左右 在阿里云OSS Go SDK中&#xff0c;bucket.UploadStream 函数并没有直接提供&#xff0c;而是通过 bucket.UploadFile 或者 bucket.PutObject 等函数来实现文件上传…...

基于 Redis 实现消息队列的深入解析

目录 Redis 消息队列简介Redis 消息队列的实现方式 2.1 使用 List 实现简单队列2.2 使用 Pub/Sub 模式实现消息发布与订阅2.3 使用 Stream 实现高级队列 Redis 消息队列的特点与优势Redis 消息队列的应用场景Redis 消息队列的局限性及应对方案总结 Redis 消息队列简介 Redis…...

C++(string类的实现)

1. 迭代器、返回capacity、返回size、判空、c_str、重载[]和clear的实现 string类的迭代器的功能就类似于一个指针&#xff0c;所以我们可以直接使用一个指针来实现迭代器&#xff0c;但如下图可见迭代器有两个&#xff0c;一个是指向的内容可以被修改&#xff0c;另一个则是指…...

nrf 24l01使用方法

1、frequency 频率基础频率2.400G HZ RF_CH RF_CH10 CH2.4G0.01G2.41G 2、逻辑通道6个 pipe 时间片不同&#xff0c;占用同一个频率 发送时&#xff0c;只有一个pipe 接受时可以有6个pipe 3、通讯速率 air data rate rf_dr 寄存器设置 有两种速率 2M 1M RF_DR0 1M ,…...

C语言普及难度三题

先热个身&#xff0c;一个长度为10的整型数组&#xff0c;输出元素的差的max和min。 #include<stdio.h> int main() {int m[10],i0,max,min;for(i0;i<10;i){scanf("%d",&m[i]);}minm[0];maxm[0];for (i 0; i <10; i){if(min>m[i]) min m[i];i…...