进程控制(详解)

article/2025/7/27 21:41:05
进程控制

上篇文章介绍了进程的相关概念,形如进程的内核数据结构task_struct 、进程是如何被操作系统管理的、进程的查看、进程标识符、进程状态、进程优先级、已经环境变量和进程地址空间等知识点;

本篇文章接着上篇文章继续对进程的控制进行展开,主要包括进程的创建fork,进程的退出和终止、写时拷贝、进程等待(防止僵尸进程的产生使得内存泄漏),进程替换的相关知识!

文章目录

      • 进程创建
        • fork()的使用场景
        • fork()调用失败的原因
        • 子进程的数据和代码默认是与父进程共享的
        • 创建子进程的操作系统需要干什么
        • 父子进程是具有独立性的
        • 父子进程既然共享代码和数据如何实现独立性
      • 写时拷贝详解
      • 进程终止
        • 进程退出的场景有哪几种?
        • 进程退出的方式
        • exit()和_exit()的区别
        • 如何获取一个进程的退出码或者退出信号
        • 方法一:通过位运算来获取
        • 方法二:通过宏来获取
      • 进程等待
        • 进程等待的用处是什么?
        • 进程等待的方式
        • wait()函数
        • waitpid()函数
        • 阻塞等待
        • 非阻塞等待
      • 进程替换
        • 为什么要有程序替换呢?
        • 原理是什么?
      • 六种程序替换函数
        • execl()
        • execlp
        • execle
        • execv()
        • execvp
        • execvpe
        • execve
        • exec系列函数用法总结:

进程创建

进程的创建在上篇文章中也有介绍过,进程创建的方式有两种,一种是我们将一个程序跑起来它就会变成一个进程,还有一种就是通过fork()函数创建子进程,主要的创建方式就是通过fork函数,所以我们再来回顾一下fork()函数吧.

fork()函数是一个系统调用接口

//fork()
pid_t fork(void);
返回值: pid_t 类型(实际上是无符号整数) 如果创建子进程成功,返回新创建的子进程的pid(大于0的)给它的父进程,返回0给它自己,如果创建失败就返回-1

注意:fork()成功创建了子进程后就会有父子两个进程,那么也就是说会有两个执行流,fork()会返回两次,分别对父进程和创建出来的子进程进行返回,给父进程返回子进程的pid,因为父进程和子进程的关系是一对多的,所以父进程需要去唯一标识子进程,而进程的pid是天然的标识一个进程的标志,所以fork()返回给父进程的是新创建出来的子进程的pid!而子进程他自己是被创建的时候就知道了自己的pid和其父进程的pid的,所以它不需要fork()函数对他返回任何值,所以fork()就默认给它返回0意思意思一下。上面是创建成功的情况,如果创建失败就会返回-1给当前进程!!!

在这里插入图片描述

fork()的使用场景

  • 一个进程希望将自己分身,可以一个人做多份工作,那么一个进程就可以通过创建子进程的方式来实现这个目的,可以将自己要干的事分担给子进程,让子进程去帮自己完成。
  • 一个进程需要执行别的可执行程序,就可以通过创建子进程的方式,让子进程通过程序替换去帮自己完成程序的执行,我们使用的shell就是这样的,我们执行命令(命令也是可执行程序)的时候,bash就会创建子进程,然后通过程序替换去执行可执行程序。

fork()调用失败的原因

原因非常简单,类比你的手机下来太多东西,容量不够了就不能在下载东西了!

所以fork()创建子进程失败的原因无非就是操作系统中存在太多的进程,内存不够了。

子进程的数据和代码默认是与父进程共享的

我们学习语言的时候了解过继承,子类会继承父类的成员变量,这个理念在进程中同样被使用!

一个进程如果通过fork()函数创建子进程成功,那么它的子进程就会以它的父进程为模板,拷贝它的代码和数据。

创建子进程的操作系统需要干什么

fork()是系统调用,那么就必须要由操作系统来完成子进程的创建工作,那么os会做什么事情呢?

  • 根据上篇文章的知识,进程是被操作系统管理起来的,一个进程就是一个task_struct结构体,该结构体包括所有的进程的属性,比如进程的pid、进程的代码对应的地址,数据对应的地址,进程的退出状态,退出信号,进程地址空间等等;

  • 操作系统用task_struct 结构体 将进程描述好,再对这些结构体管理,实现对进程的管理工作;

  • 知道了上面这些,那么我们就很容易猜到 创建一个进程操作系统就肯定会先创建一个新的task_struct 结构体,该结构体就是那个新新创建的子进程,创建好结构体还没完,还需要对其进行初始化,根据继承的理念,子进程会默认继承父进程的代码和数据,那么操作系统就会把父进程的task_struct中的代码和数据的地址拷贝给子进程;

父子进程是具有独立性的

进程之间是具有独立性的,即使是父子进程也是如此,各个进程之间都是独立运行的!

父子进程既然共享代码和数据如何实现独立性

既然子进程创建出来后是和父进程共享的代码和数据,那么子进程对继承自父进程的数据或代码进行修改,岂不是会对父进程造成影响吗?那怎么还说进程是具有独立性的呢?

  • 子进程是和父进程共享的代码和数据没错,进程间具有独立也没有错,错的是子进程修改和父进程共享的数据和代码是不可能会影响到父进程的!因为操作系统考虑到了这个问题,并且让父子进程之间具有写时拷贝的机制,使得在父子一方对共享的资源进行修改是就会将修改的资源分离使得父子各有一份,从而实现进程的独立性!!!

下面具体介绍写时拷贝~

写时拷贝详解

未发生写时拷贝:

未发生写时拷贝的时候,父子是共享这数据和代码的。 它们通过各自的页表将相同的虚拟地址映射到相同的物理地址。

在这里插入图片描述

发生写时拷贝后:

当子进程对父子共享的数据或者代码进行修改时,因为进程之间要有独立性,操作不可能直接让子进程将共享的数据给改掉,那样会直接影响到父进程!

所以操作系统会在子进程对父子共享的代码或者数据进行修改的时候,会开辟出一块新的物理空间,将要被修改的代码或者数据拷贝一份之后,让父子中先对共享资源修改的一方去修改新拷贝出来的数据,再让先修改共享资源的一方的页表去重新映射新开辟出来的物理空间实现父子进程的资源分离,互不影响!这就是写时拷贝的基本原理~ (当有一方要对共享资源修改时,为其开要修改的资源开辟新空间,再对该空间的值进行修改,使得二者都有对应的资源,但是被修改的资源不是同一块物理空间了!)

请添加图片描述

注:写时拷贝的相关操作是由操作系统的内存管理模块完成的!

为什么要有写时拷贝?直接在创建子进程的时候就为其数据和代码开辟新的空间,将其和父进程的数据和代码分离开不好么?

  • 1.父子进程的数据,子进程不一定全用,即使使用,也不一定全都会写入(修改)----------存在空间浪费
  • 2.最理想的情况是,只有会被父子修改的数据,才会进行分离拷贝,不会修改修改的共享即可 ------理论可以技术角度上无法实现,父子对数据的修改是不可提前预测的
  • 3.如果fork的时候就无脑的将父进程的数据拷贝给子进程,就会增加fork的成本(内存和时间层面上)

所以既然写时拷贝存在就有它存在的原因,存在即合理!

写时拷贝是解决上述问题的较为合理的方法,所以才会被采用。写时拷贝是一种演示拷贝的策略,只有当你会对数据进行修改的时候才会给你开辟新的空间,将数据分离,当你不修改的时候,就不会给你新开辟空间,这样省下来的空间就可以被其他进程使用了!体现了os良好的内存管理方案

进程终止

进程退出的场景有哪几种?

  • 第一种:代码运行完毕,结果正确
  • 第二种:代码运行完毕,结果不正确
  • 第三种:代码都没执行完,发生了异常,操作系统直接终止进程

进程退出的方式

  • 第一种:通过main函数返回
  • 第二种:通过调用exit()函数或系统调用_exit()退出进程
  • 第三种:给进程发信号,将进程终止(kill)

上面提到了exit()和_exit(),它们的功能都是让进程退出,两者之间有什么区别呢?

exit()和_exit()的区别

exit()是封装_exit()的函数, _exit()是系统调用。exit() 最终也还是会去调用 _exit() , exit()在 _exit()的基础上增加了新的功能,就是:

  • 执行用户通过atexit或on_exit定义的清理函数
  • 关闭所有打开的流,所有的缓存数据都会被写入(刷新)
    请添加图片描述

如何获取一个进程的退出码或者退出信号

  • exit(int status)和 _exit(int status)中的参数status就是进程的退出状态码

  • status只有低16位才有价值,它的0-7位是存储着进程的退出信号,8-15位是存的进程的退出码

  • 进程正常终止时的退出信号是为0的,退出码为进程设置的退出码

  • 进程被信号所终止时,退出码为0,退出信号为进程所收到的信号

在这里插入图片描述

方法一:通过位运算来获取

//获取退出码
status>>8&0xFF
//获取退出信号
status&0x7F
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{pid_t id=fork();if(id==0){//childint n=10;while(n--){printf("i am child! i am running pid:%d   ppid:%d\n",getpid(),getppid());sleep(1);}exit(110);}else if(id>0){sleep(10);int status=0;waitpid(id,&status,0);if(id>0){sleep(3);printf("等待子进程成功\n");printf("子进程退出码:%d   退出信号:%d  子进程pid:%d \n",status>>8&0xFF,status&0x7f,id);//位运算获取退出码和退出信号的方式}printf("父进程退出!\n");}else {printf("fork error!\n");}return 0;
}

运行结果:

在这里插入图片描述

方法二:通过宏来获取

操作系统提供对应的宏来协助我们获取对应的退出信息

说明
WIFEXITED(int status)子进程正常终止则返回真,可以通过WEXITSTATUS(int status)获取子进程退出码
WIFSIGNALED(int status)子进程异常终止返回真,若为真可通过WTERMSIG(int status)获取子进程的终止信号
WIFSTOPPED(int status)子进程若为暂停状态返回真
WIFCONTINUED(int status)子进程被暂停后将其继续的状态,返回真
WEXITSTATUS(int status)获取子进程退出码 status的次低8位
WTERMSIG(int status)获取子进程终止信号 stauts的低7位
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{pid_t id=fork();if(id==0){while(1){printf("i am child pid:%d \n",getpid());sleep(1);//exit(110);}}else {int status=0;int ret=waitpid(id,&status,0);//阻塞式等待子进程if(ret>0){// if(WIFEXITED(status)||WIFSIGNALED(status))if(WIFEXITED(status)){printf("子进程退出! 退出码:%d\n",WEXITSTATUS(status));}if(WIFSIGNALED(status)){printf("子进程退出!退出信号:%d\n",WTERMSIG(status));}}}return 0;
}

在这里插入图片描述

进程等待

进程等待的用处是什么?

我们知道子进程退出时如果父进程未读取其相关的退出信息那么该子进程就会变成僵尸进程,僵尸进程会有内存泄漏浪费系统资源,且操作系统无法回收,就算是kill 也不能将它怎么样,因为它已经僵尸了,kill可以杀死在运行的进程,但是它做不到杀死一个已经死去的进程!

  • 所以进程等待就是防止产生僵尸进程的处理方式。通过让父进程等待子进程退出,然后再读取它的退出信息,那么子进程就不再僵尸,会变成终止状态,随时等待被系统回收资源!
  • 创建子进程一般都是让子进程去完成父进程给它分配的任务,那么父进程就需要知道子进程最终完成的如何,所以父进程有必要等待子进程退出,读取它的退出状态!

进程等待的方式

wait()函数

pid_t wait(int *stauts)

wait会等待任意一个子进程

参数:

status是输出型参数,可以通过status获取退出子进程的退出状态(退出码或终止信号)

返回值:

成功返回对应子进程pid,失败返回-1

waitpid()函数

pid_t waitpid(pid_t pid,int* status,int options)

waitpid相对wait的可选性更多

参数:

pid : 为-1时,代表着等待任意一个子进程;大于0时,代表等待指定pid的子进程

status:输出型参数,可以通过它获取子进程的退出状态(退出码或终止信号)

options:等待方式,当options为0 时代表父进程阻塞式的等待子进程退出;当options为WNHANG时代表着非阻塞等待,当waitpid返回值为0时,说明子进程还未退出,父进程不会一直在那等待,而是会去干别的事,父进程会以轮询的方式来获取子进程是否退出。

返回值:等待成功返回等待的子进程的pid 失败返回-1

阻塞等待

笼统的理解

所谓的阻塞式等待就是将waitpid中的参数options设置为0,那么父进程就会一直停留在waitpid()这条语句这里,什么也不干就是干等着子进程退出,之后再往下执行后续代码。

系统的理解

父进程阻塞式等待子进程就是当子进程未退出时,操作系统会将父进程的PCB(task_sttuct)放到子进程的等待队列当中,根据前面的进程状态知识可以知道,一个进程等待着某种资源就绪的状态叫做阻塞状态,子进程在等待着父进程退出就是父进程等待着资源就绪,只要子进程不退出,那么父进程就会一直再其等待队列中,直到子进程退出,操作系统才会将父进程继续放回运行队列往下运行后续代码!!!
在这里插入图片描述

非阻塞等待

设置非阻塞等待的方式就是将waitpid()中的options设置为WNOHANG即可,那么父进程就会去询问子进程是否退出,如果退出了就返回子进程的pid,未退出返回0,出错返回-1;

通过这种返回就可以让父进程去以轮询的方式去询问子进程是否退出,如果退出就将其回收,否则父进程就可以去干其他事情,而不是一直在原地阻塞着硬等着子进程退出,非阻塞等待的方式可以解放父进程的时间!!!

进程替换

为什么要有程序替换呢?

子进程被创建出来是共享着父进程的代码的,并且会从fork()之后的代码处开始往后执行,那么执行的是和父进程一样的代码,这是没有什么意义的! 我们通常是创建子进程去让子进程去完成其他的工作,比如让子进程去执行其他的可执行程序,那么这里就需要用到进程的替换。

原理是什么?

进程替换的原理就是当进程调用exec系列的进程替换函数后,当前进程的用户空间的代码和数据就会全部被新的程序所替换,接下来就会执行的是新的程序的代码!

注意:进程替换只是将一个进程的用户空间代码和数据用新的程序的代码及数据来替换,整个过程中是没有创建新的进程的,原进程的pid是不变的,变的只有代码和数据!

请添加图片描述

六种程序替换函数

在这里插入图片描述

execl()

int execl(const char *path, const char *arg, ...);

函数名中的l代表list,指代传执行程序的方式是按列表的方式传参的

参数列表

path:代表着要执行的程序的绝对路径

arg:执行该程序的方式,这里的arg是一个可变参数列表。(执行指令方式的多个字符串都可以被arg接收),但是传给arg的最后一个字符串必须是NULL

例如:执行ls 命令时 我们敲的是 ls -a -l

那么让ls去替换子进程时,首先path 就是传的ls的绝对路径(/usr/bin/ls),剩下的就是我们的执行方式 ls -a -l 那么arg就得是“ls" “-a” “-l”,当然最后得串一个空代表执行命令结束了,所以传给arg的是"ls",“-a”,“-l”,NULL

在这里插入图片描述

执行结果:子进程执行了ls(ls是一个命令 ,也是一个程序!)
在这里插入图片描述

execlp

int execlp(const char *file, const char *arg, ...);

解释

函数名中的p代表着PATH的意思,带p的替换函数就会自动去搜索环境变量PATH;

所以在带p的替换函数中执行某个程序的时候就可以不用传某个程序的绝对路径,只需传其程序名即可,程序替换函数会自己去环境变量中去找这个程序。

参数列表

第一个就是替换的程序路径(不用写全),第二个就是可变参数列表,接收的是执行的方式,同execl.

在这里插入图片描述

execle

int execle(const char *path, const char *arg,..., char * const envp[]);

解释

  • 函数名带l,说明传参方式是列表;

  • 函数名中的e代表着environment的意思,也就是环境变量了。execle函数可以自己组装环境变量。

在这里插入图片描述

在这里插入图片描述

execv()

int execv(const char *path, char *const argv[]);

解释

path代表着执行的程序的绝对路径;

argv代表着执行替换程序的方式,用数组的方式传参。

在这里插入图片描述

execvp

解释

execvp和execlp只相差了一个字母,一个是l,一个是v,l代表list(列表),v代表vecor(数组)

也就是带l的执行程序的方式是以列表的方式传递的,带v的则以数组的方式传递!

在这里插入图片描述

execvpe

解释

类比execle和execlp,带v可知execvp的程序的执行方式以数组形式传递,带p可知其会自己搜索环境变量PATH,带e可知该函数可以自己组装环境变量。

在这里插入图片描述

execve

上面的六个函数都是语言封装的execve函数 execve是系统调用

注意:

  • exec系列的函数的参数args,是接收的程序执行的方式,其必须以NULL结尾!

exec系列函数用法总结:

函数名args(执行方式)的传参形式是否带路径(PATH)是否使用当前环境变量
execl(list)列表
execlp列表
execle列表自己组装环境变量
execv(vector)数组
execvp数组
execvpe数组自己组装环境变量
execve数组自己组装环境变量

http://chatgpt.dhexx.cn/article/KJJQvbtc.shtml

相关文章

c++跨平台技术学习(三)--使用标准API

Posix.1 API定义了大量的函数&#xff0c;在各方面的功能都很丰富&#xff0c;下面对其进行介绍 System V接口定义 它是一份描述了AT&T UNIX System V操作系统的文档&#xff0c;与POSIX.1保持一致&#xff0c;是它的一个超集。SVID由基础系统和扩展定义&#xff0c;它只…

BUUCTF刷题记录 Ping Ping Ping

[GXYCTF2019]Ping Ping Ping 进入页面 然后/?ip127.0.0.1|ls 进入 读取flag.php 再cat$IFS$1indnx.php 再变量拼接 ?ip127.0.0.1;ag;cat$IFS 1 f l a 1fla 1flaa.php 转至 http://1d22a0a5-c6a0-43f1-8e52-e5a33ec7e044.node3.buuoj.cn/?ip127.0.0.1;ag;cat$IFS 1 f l a …

JVM 答疑解惑

JVM是什么&#xff1f; 平常接触的东西都存在哪里&#xff1f; 类如何加载&#xff1f; 怎么运行&#xff1f; 清洁工怎么工作&#xff1f; JVM是什么&#xff1f; Java 虚拟机屏蔽了与具体操作系统平台相关的信息,使得 Java 语言编译程序只需生成在 Java 虚拟机上运行的目…

2021-CISCN西南赛区线下-misc-stealer

stealer 题目描述&#xff1a; stealer 那女孩对我说说我是一个小偷&#xff08;本题flag 格式为 DASCTF{}&#xff0c;提交时只需要提交括号中间的字符。flag需小写&#xff09; hint&#xff1a;MISC-stealer: focus on DNS CRYPTO 知识点 1.DNS后面的base64 2.然后base6…

CVPR 2019|PoolNet:基于池化技术的显著性检测 论文解读

作者 | 文永亮 研究方向 | 目标检测、GAN 研究动机 ​ 这是一篇发表于CVPR2019的关于显著性目标检测的paper&#xff0c;在U型结构的特征网络中&#xff0c;高层富含语义特征捕获的位置信息在自底向上的传播过程中可能会逐渐被稀释&#xff0c;另外卷积神经网络的感受野大小与深…

请问做亚马逊,注册P卡是用个人名义还是公司名义?

请问做亚马逊&#xff0c;注册P卡是用个人名义还是公司名义&#xff1f;亚马逊将Payoneer作为亚马逊卖家平台里的推荐收款方式。24个不同国家的卖家能够使用亚马逊卖家中心唯一推荐的收款方式——Payoneer来收款&#xff0c;接收、使用亚马逊货款变得前所未有地简便。 个人、公…

解决CentOS7 Ping不了外网的问题 ping:baidu.com: 未知的名称或服务

在CentOS7中遇到个问题&#xff0c;ping外网地址时候提示“未知的名称或服务” 先使用该命令查看路由网关信息 route -n 发现没有配置网关地址&#xff1a; ​​​​​​​ 去虚拟机里的虚拟网络编辑器里查看下网关地址 然后将网关地址配置到路由中 &#xff08;临时有效&…

BUUCTF Web [GXYCTF2019]Ping Ping Ping

「作者主页」&#xff1a;士别三日wyx 此文章已录入专栏《网络攻防》&#xff0c;持续更新热门靶场的通关教程 「未知攻&#xff0c;焉知收」&#xff0c;在一个个孤独的夜晚&#xff0c;你完成了几百个攻防实验&#xff0c;回过头来才发现&#xff0c;已经击败了百分之九十九…

[GXYCTF 2019]Ping Ping Ping

前言 之前没总结过关于命令执行的绕过姿势&#xff0c;借着今天做的这个命令执行的题目来总结一下。 先看题目 题目 题目很单一&#xff0c;目的就是为了让我们通过参数传入内容来执行代码。因为题目是与ping有关&#xff0c;当我们输入127.0.0.1时&#xff0c;它会进行ping…

[GXYCTF2019]Ping Ping Ping(命令执行)

命令执行绕过 常见写法 127.0.0.1&&code 只有在 && 左边的命令返回真&#xff08;命令返回值 $? 0&#xff09;&#xff0c;&& 右边的命令才 会被执行。 127.0.0.1&code &表示将任务置于后台执行 127.0.0.1||code 只有在 || 左边的命令返回…

CTF_Web_[GXYCTF2019]Ping Ping Ping

一、题目 Ping Ping Ping 二、靶机信息链接 靶机信息 剩余时间: 10072s http://70284b15-7c4e-4548-8b04-aadbc6e669f5.node4.buuoj.cn:81 三、靶机链接页面 四、 分析 因题目是Ping...再加上靶机页面有“/?ip” 可能是 ping地址&#xff0c;尝试按照所给的内容在url中加…

BUUCTF [GXYCTF2019]Ping Ping Ping easywill

题目地址&#xff1a;BUUCTF在线评测 考点&#xff1a;ping命令相关命令执行 这里过滤了flag和空格 绕过空格可以使用 $IFS$1 使用ls命令查询目录 ?ip127.0.0.1;ls 发现有两个文件&#xff0c;一个是flag.php&#xff0c;另一个是index.php。 cat获取文件内容&#xff…

BUUctf [GXYCTF2019]Ping Ping Ping

根据题目和页面的提示猜测是命令执行漏洞 ;前面和后面命令都要执行&#xff0c;无论前面真假 |直接执行后面的语句 ||如果前面命令是错的那么就执行后面的语句&#xff0c;否则只执行前面的语句 &前面和后面命令都要执行&#xff0c;无论前面真假 &&如果前面为假&a…

BUUCTF——web([GXYCTF2019]Ping Ping Ping、[极客大挑战 2019]Knife、[极客大挑战 2019]Http)

BUUCTF-web [GXYCTF2019]Ping Ping Ping做题思路 [极客大挑战 2019]Knife做题思路 [极客大挑战 2019]Http做题思路 [GXYCTF2019]Ping Ping Ping 做题思路 打开看题目 熟悉的样子&#xff0c;ping本地加查看命令&#xff0c;得到两个php文件 接着查看一下文件内容 奇奇怪…

Buuctf (Web)Ping Ping Ping

文章目录 一.解题步骤二、命令分隔符三.常见绕过方式 一.解题步骤 &#xff08;1&#xff09;页面里显示/?ip,很明显要以ping的形式传一个参数给ip&#xff0c;并且我们要想执行其他命令&#xff0c;就要用命令分隔符也就是管道符连接&#xff0c;命令分隔符可以用";“”…

BUUCTF之Ping Ping Ping

目录 审题 常用的空格绕过方法 解决方法 法一 拼接绕过法 法二 内联执行法 法三 sh编码绕过法 审题 点开链接 根据题目提示随便试试构造payload inurl?ip666 有返回&#xff0c;参数ip的值就是要ping的内容 这里我们知道有Windows和Linux通用的…

BUUCTF【Web】Ping Ping Ping

进入靶场后是一个ping的功能&#xff08;命令执行漏洞&#xff09;&#xff0c;参数ip传递的内容会被当做ip地址进行网络连通性测试。首先测试一下本机地址 首先使用ls命令查看当前路径下有那些文件&#xff0c;拼接符有“&”、“|”、“||”、“&&”、“&#xff…

BUUCTF Web [GXYCTF2019]Ping Ping Ping [极客大挑战 2019]LoveSQL [极客大挑战 2019]Knife [极客大挑战 2019]Http

目录 [GXYCTF2019]Ping Ping Ping [极客大挑战 2019]LoveSQL [极客大挑战 2019]Knife [极客大挑战 2019]Http [GXYCTF2019]Ping Ping Ping 启动靶机&#xff0c;构造payload ?ip127.0.0.1 查看同目录下有什么文件 ?ip127.0.0.1;ls 读取flag.php ?ip127.0.0.1;cat flag…

buuctf[GXYCTF2019]Ping Ping Ping

buuctf[GXYCTF2019]Ping Ping Ping 这个题目的标题是pingping盲猜是关于命令执行的题目 打开环境后 只有一个/ip&#xff1f; 应该是提示用get的方式来传参一个地址执行ping的操作 直接ping127.0.0.1 回显ping127.0.0.1的数据 说明是一道命令执行的题目 执行&#xff1a;?i…

xxl-job源码阅读——(六)调度线程与时间轮算法

文章目录 一. 时间对齐二. scheduleThread 调度线程三. ringThread 时间轮&#xff08;算法&#xff09;线程原理源码实现 本章介绍init()最后一个步骤&#xff0c;初始化调度线程。 另外 第六步的JobLogReportHelper.getInstance().start()只是做了一个日志整理收集&#xff0…