Linux信号解析

news2024/12/22 9:34:53

在这里插入图片描述

文章目录

  • Linux信号概念
  • 信号种类
  • Linux信号产生
    • 异步
  • LInux信号阻塞
    • 递达、未决、阻塞、忽略
    • 信号集操作函数
    • 阻塞信号集操作函数
    • 未决信号集操作函数
  • Linux信号捕捉
    • signal函数
    • sigaction函数
  • 总结

Linux信号概念

信号在我们的生活中无处不在,常见的如电话铃声,闹钟等,这些的信号都是给我们传达某些信息,在接收到信息之后来选择采取什么样的措施,因此我们可以将信号理解为传达信息的事物。在Linux中也有这么一批信号,信号是操作系统提供的一种机制,用于通知进程发生了某种事件或异常情况。当特定的事件发生时(例如按下 Ctrl+C 来中断程序),操作系统会生成相应的信号,并将其发送给目标进程。总之,信号是操作系统提供的一种重要的进程间通信机制,操作系统捕获和分发信号,允许进程对信号进行响应和处理。

信号种类

Linux中有多种不同的信号,每个信号都有一个编号和一个宏定义名称,例如1表示SIGHUP,2表示SIGINT等等,这些宏定义可以在signal.h中找到。

在这里插入图片描述

在linux中也可以用kill -l命令来查看信号,以下信号可以分为两个主要类别:实时信号和标准信号。实时信号是为了满足实时应用程序的需求而引入的,具有较高的优先级和可预测的传递和处理时间。实时信号的信号编号通常在34到64之间,例如SIGRTMIN、SIGRTMIN+1等。它们具有实时信号队列,按照顺序接收和处理,以确保信号的顺序性。实时信号有两个优先级:实时信号和实时时钟信号。

标准信号是常规的信号类型,用于各种进程通信、控制和处理异常情况。标准信号的信号编号通常在1到31之间,包括SIGINT、SIGHUP、SIGTERM等。它们没有明确定义的优先级,信号处理通常较为基本。这两种信号类型都用于与进程通信、控制进程行为和处理各种事件。实时信号主要用于实时应用,而标准信号则更常用于一般用途的进程间通信和控制。

在这里插入图片描述

Linux信号产生

Linux信号可以通过多种方式产生,通常由内核、其他进程或硬件事件触发。例如进程终止或错误时也会产生信号进程执行发生错误时,如除以零,产生SIGFPE信号,进程访问未分配给它的内存或无效内存时,产生SIGSEGV信号。当用户在终端按下Ctrl+C会产生SIGINT信号。用户在终端按下Ctrl+\,产生SIGQUIT信号。用户按下Ctrl+Z,将进程置于后台并产生SIGTSTP信号。

在某些情况下,系统调用失败也会产生特定的信号,如SIGPIPE。这些信号产生方式可以由操作系统、应用程序或用户发起。处理这些信号可以通过注册信号处理函数来定义接收到信号时要执行的特定操作。例如可以使用kill命令向另一个进程发送信号。

在这里插入图片描述

此外还可以使用kill()函数向另一个进程发送信号,kill 函数通常用于终止一个进程。它是Unix和类Unix操作系统中的系统调用之一。

在这里插入图片描述

它的参数 pid代表的是要终止的进程的进程ID(PID)。sig表示要发送给目标进程的信号。通常,SIGTERM(15号信号)用于请求优雅地终止进程,而SIGKILL(9号信号)用于强制终止进程。

在这里插入图片描述

如果成功发送信号,则返回0。如果失败,则返回-1,并设置errno来指示错误的原因。如下代码:

void Usage(string str)
{
    cout << "Usage : \n\t";
    cout << str << "int sig   pid_t pid" << endl;
}

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    int signo = atoi(argv[1]);
    int target_id = atoi(argv[2]);
    int ret = kill(target_id, signo);  //给指定进程发送指定信号
    if(ret == -1)
    {
        cout << errno << strerror(errno) << endl;
    }
    return 0;
}

这是一个简单的C++程序,用于给指定的进程发送信号。Usage 函数用于打印程序的用法说明,它接受一个字符串参数 str,用 cout 打印用法信息。main 函数首先检查命令行参数的数量,如果不等于3个(期望的参数数量),则调用 Usage 函数打印用法信息,并使用 exit(1) 终止程序。如果命令行参数数量正确,它将解析这两个参数为整数 signo 和 target_id,分别表示要发送的信号和目标进程的PID。然后,调用 kill 函数来向指定的进程发送指定的信号,并将返回值存储在 ret 变量中。最后,程序检查 kill 函数的返回值,如果返回值为-1,表示发送信号失败。它将使用 errno 和 strerror 函数来打印错误信息。结果如下:

在这里插入图片描述

异步

异步是指在程序执行过程中,某个操作可以独立于主程序流程,不阻塞主程序的执行,而在完成后通知主程序或回调执行相应的处理。简而言之,异步操作允许程序在等待某些事件完成的同时,可以继续执行其他任务。举例来说,假设你在下载一个大文件,如果是同步操作,程序会一直等待下载完成才能进行其他操作。而异步下载则会允许你在下载的同时执行其他任务,当下载完成时会通过回调或其他机制通知你。异步通常用于处理需要等待的操作,比如网络请求、文件读写、图形界面事件等。它可以提高程序的响应性和效率,因为在等待某些操作完成的同时,可以执行其他任务,充分利用了计算资源。

而信号相对于进程的控制流程来说就是异步的,因为对于进程来说,信号来源不确定,信号可以来自多种来源,包括其他进程、操作系统或硬件事件。进程无法预测何时会收到信号,因此无法像在同步控制流程中那样精确地安排信号的处理。并且信号可以随时中断进程,当进程正在执行某个任务时,随时可能收到信号。这个信号会中断进程当前的执行,转而执行与信号相关联的信号处理函数。这种中断式的行为使得信号处理是异步的,因为进程无法控制何时会被中断。信号处理被时间也是不确定的,信号处理函数的执行时间是不确定的,取决于信号的类型和处理函数的复杂性。进程无法预测信号处理将花费多长时间,因此无法以确定的方式管理信号的异步性质。

综上所述,可以说信号相对于进程的控制流程来说是异步,因为它们可以在进程不预期的时间中断进程的执行,且信号的来源和处理时间都是不确定的,无法由进程精确地控制。这使得处理信号的机制更加灵活,但也需要谨慎处理,以确保进程的稳定性和可靠性。

LInux信号阻塞

Linux中的信号阻塞是一种机制,它可以防止特定信号在某段代码执行期间被中断。这样可以确保关键部分的代码不会被信号中断,从而保证程序的一致性和可靠性。

递达、未决、阻塞、忽略

递达、未决、阻塞、忽略这些术语通常用于描述与信号处理相关的状态和操作:

  • 信号递达(Delivered):表示信号已经成功传递给目标进程,但目标进程尚未开始处理信号。信号已经到达进程的信号队列中,等待被处理。
  • 信号未决(Pending):未决状态表示信号已经递达,但目标进程还没有处理完该信号。在某些情况下,一个进程可以同时拥有多个未决信号,这些信号排队等待处理。
  • 信号阻塞(Blocked):阻塞表示进程已经将某些信号阻塞,即在信号掩码中将这些信号的位设置为1。阻塞信号的目的是防止它们在关键代码段执行期间中断进程。
  • 信号忽略(Ignored):忽略表示进程对特定信号的处理方式是忽略。当进程忽略信号时,该信号不会触发默认的操作或用户定义的信号处理函数,而会被静默忽略。

这些概念一起用于描述进程如何处理信号。例如,一个进程可以选择忽略某些信号,将其他信号阻塞以在关键部分执行时不被中断,然后处理已递达但未决的信号。递达和未决信号的状态告诉我们哪些信号已经到达,哪些正在等待被处理。信号处理是进程中管理这些状态的关键部分。

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

信号集操作函数

在操作系统中,通常会有三张表与信号处理相关:阻塞表(Block Table)、未决表(Pending Table) 和 处理程序表(Handler Table)。这些表用于管理和描述进程的信号处理状态和方式。

block表维护了有关哪些信号被当前进程阻塞的信息,对于每个进程,内核会维护一个信号掩码,该掩码是一个位掩码,用于表示哪些信号被阻塞,哪些可以传递给进程。控制信号掩码可以通过系统调用如 sigprocmask 进行,使进程可以选择性地阻塞或解除阻塞信号。

pending表记录了哪些信号已经被递送给进程,但尚未被处理。每个进程都有一个未决信号集合,这些信号在被递送后保持未决状态,直到被处理。未决信号的状态可以在内核中进行管理,以确保每个信号都得到适当的处理。

handler表是一个数据结构,用于将信号与它们的处理方式(处理函数)相关联。对于每个信号,内核会维护一个处理程序表,记录了该信号的默认操作或用户自定义处理函数。当进程接收到一个信号时,内核会查找相应信号的处理程序表,并执行与之相关联的处理函数。

这三张表协同工作,允许进程管理信号的接收和处理。阻塞表控制哪些信号会被阻塞,未决表跟踪哪些信号等待处理,而处理程序表定义了每个信号的行为。这些机制使进程能够在异步情况下处理信号,以应对不同类型的事件和通信。

Linux中常规信号在递达之前产生多次的话只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里统计多次。

从这里就可以知道,每个信号只有一个 bit 的未决和阻塞标志,不是0就是1。因此在Linux中未决和阻塞标志可以用相同的数据类型sigset_t来存储。sigset_t 是一个数据类型,通常用于表示信号集合,用于管理和操作一组信号的状态。它是 POSIX 标准中定义的一种数据类型,用于在信号处理中指定和操作一组信号。sigset_t 通常是一个用于存储信号掩码的数据结构。信号掩码是一个位掩码,其中每一位对应一个特定的信号。如果某个信号的位被设置为 1,表示该信号被阻塞;如果为 0,表示该信号可以传递给进程。通过设置和修改 sigset_t 对象,可以实现对信号的阻塞和解除阻塞。以下是一些与 sigset_t 相关的常用函数和操作:

在这里插入图片描述

  • sigemptyset(sigset_t *set):用于初始化一个空的信号集合,即将所有信号位都设置为 0。
  • sigfillset(sigset_t *set):用于将一个信号集合设置为包含所有可能的信号,即将所有信号位都设置为 1。
  • sigaddset(sigset_t *set, int signum):用于将指定信号添加到信号集合中,将对应信号位设置为 1。
  • sigdelset(sigset_t *set, int signum):用于从信号集合中移除指定信号,将对应信号位设置为 0。
  • sigismember(const sigset_t *set, int signum):用于检查指定信号是否包含在信号集合中。

在这里插入图片描述

sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。其他四个函数都是成功返回0,出错返回-1。sigset_t 对象通常在信号处理函数中使用,以防止在关键代码段执行时被特定信号中断。通过操作 sigset_t 对象,可以实现对信号的精细控制和管理。

阻塞信号集操作函数

对于进程的阻塞信号集可以调用函数sigprocmask来读取或更改,sigprocmask 是一个 POSIX 标准定义的系统调用,该系统调用的函数原型如下:

在这里插入图片描述
其中 how 参数指定了如何修改信号屏蔽字,有以下3种选择:

  • SIG_BLOCK:将 set 中的信号添加到当前的信号屏蔽字中。
  • SIG_UNBLOCK:从当前的信号屏蔽字中移除 set 中的信号。
  • SIG_SETMASK:将当前的信号屏蔽字设置为 set 中的值。

set 参数和 oldset 参数都是一个指向 sigset_t 类型的指针,set 参数包含了要设置的新的信号屏蔽字。oldset 参数用于存储调用 sigprocmask 前的信号屏蔽字。如果不关心原始的信号屏蔽字,可以将 oldset 设为 NULL。

未决信号集操作函数

对于进程的未决信号集可以用 sigpending 函数来查看,sigpending 是一个 POSIX 标准定义的函数,用于检索当前进程中的未决信号,函数原型如下:

在这里插入图片描述
set 参数是一个指向 sigset_t 类型的指针,用于存储检测到的未决信号。这个函数会将当前进程中的未决信号的信号集合存储到 set 中。sigpending 函数通常在信号处理程序中使用,以确定哪些信号在当前上下文中已经到达但尚未被处理。未决信号的检查可以帮助进程采取相应的行动来处理这些信号,比如选择性地解除信号阻塞、执行相应的处理程序等。

未决信号是在 sigpending 函数被调用时确定的,因此在函数返回后,仍然可能会有新的信号到达并成为未决信号。

Linux信号捕捉

Linux的信号产生之后,就需要有东西能接收到这个信号,然后在决定接收到这个信号后采取什么样的措施。如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。

signal函数

在Linux中,可以通过注册信号处理函数来捕捉信号,以定义在接收到特定信号时要执行的操作。其中就可以使用signal()函数来对信号进行捕捉处理,signal()函数是用于在Linux和UNIX系统中注册信号处理函数的函数之一,它的原型如下:

在这里插入图片描述

signal()函数的主要作用是告诉操作系统,在接收到特定信号(由signum指定)时,去调用特定的信号处理函数(由handler指定)。这个函数返回一个函数指针,该指针指向以前注册的信号处理函数(通常是默认处理方式)。一般你可以忽略这个返回值,但如果需要以后恢复默认的信号处理行为的话就可以使用它。如下代码:

int main()
{
    while(1)
    {
        cout << "run......." << endl;
        sleep(1);
    }
    return 0;
}

代码是一个死循环,当我们按下Ctrl + C的时候进程会收到一个2号信号SIGINT从而结束进程。

在这里插入图片描述
但是当使用signal函数对2号信号进行自定义捕捉时,这时候再去按下Ctrl + C就不再是执行默认动作结束进程,而是去执行我们的自定义动作,如下代码:

void handler(int signo)
{
    cout << "get signo : " << signo << endl;
}

int main()
{
    signal(2, handler);
    while(1)
    {
        cout << "run......." << endl;
        sleep(1);
    }
    return 0;
}

在这段代码中,当按下Ctrl + C发送2号信号时,程序会去执行handler方法并打印出捕捉到的信号。

在这里插入图片描述

sigaction函数

sigaction 是一个 POSIX 系统调用,用于检查或修改进程的信号处理行为。与 signal 函数相比,sigaction 提供了更完整和灵活的控制机制来管理信号处理。以下是 sigaction 的函数原型:
在这里插入图片描述
其中参数 signum表示指定要操作的信号。act 是一个指向 struct sigaction 的指针,该结构描述了新的信号处理行为。参数 oldact 是一个指向 struct sigaction 的指针,用于保存之前的信号处理行为。如果不关心之前的行为,可以设置为 NULL。

在这里插入图片描述

struct sigaction 结构包含以下主要字段:

  • sa_handler:指向信号处理函数的指针。
  • sa_sigaction:用于更高级的信号处理,并提供关于信号的更多信息。
  • sa_mask:在处理该信号时要阻塞的其他信号集合。
  • sa_flags:用于指定各种信号处理选项。
  • sa_restorer:此字段已不再使用,但在一些旧的系统中仍然存在。

在这里插入图片描述

sa_flags 可能包括以下选项之一或多个:

  • SA_NOCLDSTOP:如果信号是 SIGCHLD,则在子进程停止或继续时不会产生该信号。
  • SA_NOCLDWAIT:使父进程在其子进程终止时不创建僵尸进程。
  • SA_NODEFER:不将处理的信号自动添加到信号掩码中。
  • SA_ONSTACK:使用为信号专门定义的备用堆栈,如果有的话。
  • SA_RESETHAND:在信号处理程序被调用后,将信号的处理程序重置为默认值。
  • SA_RESTART:使某些被信号中断的系统调用重新启动。
  • SA_SIGINFO:指示信号处理程序应该使用 sa_sigaction 字段而不是 sa_handler。

总的来说,sigaction 提供了一个强大的机制来查看和更改信号处理行为。由于它提供了对信号处理的详细控制,所以它通常被推荐为设置信号处理程序的首选方法。如下代码:

void sighandler(int signo)
{
    cout << "get signo : " << signo << endl;
}
int main()
{
    struct sigaction act, oldact;
    memset(&act, 0, sizeof(act));
    memset(&oldact, 0, sizeof(oldact));
    act.sa_handler = sighandler;
    act.sa_flags = 0;

    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, 2);
    sigaddset(&act.sa_mask, 3);

    sigaction(2, &act, &oldact);
    sigaction(3, &act, &oldact);

    while(1)
    {
        cout << "PID : " << getpid() << endl;
        sleep(1);
    }
    return 0;
}

这段代码设置了信号处理函数 sighandler,然后通过 sigaction 函数为信号2和信号3分别设置了新的信号处理方式,同时设置了信号屏蔽集,以确保在处理这些信号时不会被其他信号中断。然后,程序进入无限循环,输出PID,并持续运行,等待信号的触发。当信号2或3被触发时,将会调用 sighandler 函数来处理它们。
在这里插入图片描述

总结

文章中介绍了Linux中信号的概念、信号的种类以及信号的产生方式进行分析,并对Linux信号的阻塞和捕捉函数进行分析,对函数的参数逐一分析,并提供示例代码供参考。总之,Linux信号是一种重要的进程通信机制,允许进程之间以及操作系统与进程之间进行异步通信,以响应各种事件和异常情况。了解如何正确使用和处理信号对于编写可靠的Linux应用程序至关重要。

码文不易,客官如果觉得文章对你有帮助的话就来一个三连吧👍。

在这里插入图片描述

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

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

相关文章

openstack-ansible部署zed版本all-in-one

目录 部署架构部署节点准备安装Rocky linux 9配置rocky 目标节点配置网络配置rocky linux网卡的创建永久网桥的方法&#xff1a; 部署前配置 部署架构 可用的操作系统&#xff1a; Debian11&#xff08;bullseye&#xff09; Ubuntu 22.04或20.04 CentOS Stream 9 或 Rocky Lin…

【Golang】网络编程

网络编程 网络模型介绍 OSI七层网络模型 在软件开发中我们使用最多的是上图中将互联网划分为五个分层的模型&#xff1a; 物理层数据链路层网络层传输层应用层 物理层 我们的电脑要与外界互联网通信&#xff0c;需要先把电脑连接网络&#xff0c;我们可以用双绞线、光纤、…

CocosCreator3.8研究笔记(二十五)CocosCreator 动画系统-2d骨骼动画spine

大家都知道&#xff0c;在游戏中 一般用帧动画或者骨骼动画&#xff0c;实现 人物的行走、奔跑、攻击等动作。 帧动画&#xff0c;在上一篇已经做了介绍&#xff0c;感兴趣的朋友可以前往阅读&#xff1a; CocosCreator3.8研究笔记&#xff08;二十四&#xff09;CocosCreator …

10.5作业

磕磕绊绊还是差不多完成了,tcp多客户端在线词典 代码&#xff1a; 数据库导入&#xff1a;有点粗糙&#xff0c;不知道怎么搞成两列&#xff0c;一个单词中间还是空格卧槽难搞 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <s…

NPDP产品经理知识(产品创新流程)

1.复习组合管理: 组合管理的目标 ===> 价值最大化,项目平衡,战略一致,管道平衡(资源需求和供给),盈利充分 (实现财务目标) 产品创新流程就是管理风险的过程。 模糊前端: 产品创新章程:PIC 包含 =====> 背景,聚焦舞台,目标和目的,特别准则,可持续性 新产…

mysql面试题13:MySQL中什么是异步复制?底层实现?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:讲一讲mysql中什么是异步复制?底层实现? MySQL中的异步复制(Asynchronous Replication)是一种复制模式,主服务器将数据写入二进制日志后,无…

计组——I/O方式

一、程序查询方式 CPU不断轮询检查I/O控制器中“状态寄存器”&#xff0c;检测到状态为“已完成”之后&#xff0c;再从数据寄存器取出输入数据。 过程&#xff1a; 1.CPU执行初始化程序&#xff0c;并预置传送参数&#xff1b;设置计数器、设置数据首地址。 2. 向I/O接口发…

星际争霸之小霸王之小蜜蜂(十六)--狂奔的花猫

系列文章目录 星际争霸之小霸王之小蜜蜂&#xff08;十五&#xff09;--剧将终场 星际争霸之小霸王之小蜜蜂&#xff08;十四&#xff09;--资本家的眼泪 星际争霸之小霸王之小蜜蜂&#xff08;十三&#xff09;--接着奏乐接着舞 星际争霸之小霸王之小蜜蜂&#xff08;十二…

视频讲解|含可再生能源的热电联供型微网经济运行优化(含确定性和源荷随机两部分代码)

1 主要内容 该视频为《含可再生能源的热电联供型微网经济运行优化》代码讲解内容&#xff0c;对应的资源下载链接为考虑源荷不确定性的热电联供微网优化-王锐matlab&#xff08;含视频讲解&#xff09;&#xff0c;对该程序进行了详尽的讲解&#xff0c;基本做到句句分析和讲解…

路径问题【动态规划】

一、不同路径 class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m1,vector<int>(n1));dp[0][1] 1;for(int i 1;i < m;i){for(int j 1;j < n;j){dp[i][j] dp[i-1][j]dp[i][j-1];}}return dp[m][n];} }; 二、不同路…

三、thymeleaf基本语法

3.1、基本语法 3.1.1变量表达式&#xff1a;${...} 变量表达式用于在页面中输出指定的内容&#xff0c;此内容可以是变量&#xff0c;可以是集合的元素&#xff0c;也可以是对象的属性。主要用于填充标签的属性值&#xff0c;标签内的文本&#xff0c;以及页面中js变量的值等…

OpenCV项目开发实战--CUDA 模块使用详细介绍--附完整代码

如果您已经使用 OpenCV 一段时间,您应该已经注意到,在大多数情况下 OpenCV 使用 CPU,这并不总能保证您获得所需的性能。为了解决这个问题,2010 年 OpenCV 中添加了一个使用 CUDA 提供 GPU 加速的新模块。您可以在下面找到展示 GPU 模块优势的基准测试: 图 1: CPU 上的 Op…

Day-06 基于 Docker安装 Nginx 镜像

1.去官方公有仓库查询nginx镜像 docker search nginx 2.拉取该镜像 docker pull nginx 3. 启动镜像&#xff0c;使用nginx服务&#xff0c;代理本机8080端口(测试是不是好使) docker run -d -p 8080:80 --name nginx-8080 nginx docker ps curl 127.0.0.1:8080

黑马程序员 MySQL数据库入门到精通——进阶篇(2)

黑马程序员 MySQL数据库入门到精通——进阶篇&#xff08;2&#xff09; 1. SQL优化1.1 插入数据1.2 主键优化1.3 order by优化1.4 group by优化1.5 limit优化1.6 count优化1.7 update优化 2. 视图2.1 视图-介绍及基本语法2.2 视图-检查选项(cascaded)2.3 视图-检查选项(local)…

SQL Server不允许保存更改的解决方法

SQL Server不允许保存更改的解决方法

深信服SG上网优化管理系统存在任意文件读取漏洞 附POC

文章目录 深信服SG上网优化管理系统存在任意文件读取漏洞 附POC1. 深信服SG上网优化管理系统简介2.漏洞描述3.影响版本4.fofa查询语句5.漏洞复现6.POC&EXP7.整改意见8.往期回顾 深信服SG上网优化管理系统存在任意文件读取漏洞 附POC 免责声明&#xff1a;请勿利用文章内的…

软件设计师_计算机网络_学习笔记

文章目录 4.1 网路技术标准与协议4.1.1 协议4.1.2 DHCP4.1.3 DNS的两种查询方式 4.2 计算机网络的分类4.2.1 拓扑结构 4.3 网络规划与设计4.3.1 遵循的原则4.3.2 逻辑网络设计4.3.3 物理网络设计4.3.4 分层设计 4.4 IP地址与子网划分4.4.1 子网划分4.4.2 特殊IP 4.5 HTML4.6 无…

C++入门-day01

一、认识C C融合了三种不同的编程方式 C代表的过程性语言在C基础上添加的类、结构体puls代表的面向对象语言C模板支持泛型编程 C完全兼容C的特性 Tips&#xff1a;侯捷老师提倡的Modren C是指C11、C14、C17和C20这些新标准所引入的一系列新特性和改进。在我们练习的时候也应当去…

QT实现TCP服务器客户端的实现

ser&#xff1a; widget.cpp&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器server new QTcpServer(this);// 此时&#xf…

MyBatisPlus(八)范围查询

说明 范围查询&#xff0c;包括&#xff1a; 大于大于等于小于小于等于在范围内在范围外 大于&#xff1a;gt 代码 Testvoid gt() {LambdaQueryWrapper<User> wrapper new LambdaQueryWrapper<>();wrapper.gt(User::getAge, 20);List<User> users mapp…