关于Linux下的进程替换(进程篇)

目录

进程替换是什么?

进程替换需要怎样操作?

 替换函数

 命名理解

不创建子进程进行进程替换

关于替换程序时的写时拷贝

fork创建子进程进行替换

函数1:execl

函数2:execv

函数3:execlp

函数4:execvp

函数5:execle


进程替换是什么?

父进程fork()创建子进程之后,父子各自执行父进程代码的一部分

父子进程代码共享,数据写时拷贝各自一份

那么此时,子进程想执行一个全新的程序呢? 子进程想有自己的代码呢??应该怎么办?

此时就需要进程替换,来完成这个功能。

官方的说法是:程序替换,是通过特定的接口,加载磁盘上的一个权限的程序(代码和数据),加载到调用进程的地址空间中!

可参考:进程的创建  程序地址空间

fork常规用法
一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。---就叫做程序替换

图例:

  • 进程替换,有没有创建新的子进程? 没有!
  • 那么如何理解所谓的将程序放入内存中!   是通过加载!
  • 所谓的exec*函数本质,就是如何加载程序的函数!
  • 编译有编译器,加载也有加载器注意磁盘和内存都是硬件,那么加载的时候,系统会提供相关函数来进行把磁盘的数据搬到内存中就是加载
     

进程替换需要怎样操作?

a.不创建子进程进行进程替换(无意义,主要用于演示)

b.fork创建子进程进行替换

替换函数

EXEC(3)                                                         Linux Programmer's Manual                                                         EXEC(3)

NAME
       execl, execlp, execle, execv, execvp, execvpe - execute a file

SYNOPSIS
       #include <unistd.h>

       extern char **environ;

       int execl(const char *path, const char *arg, ...);
       int execlp(const char *file, const char *arg, ...);
       int execle(const char *path, const char *arg,
                  ..., char * const envp[]);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                   char *const envp[]);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       execvpe(): _GNU_SOURCE

 命名理解

这些函数原型看起来很容易混 , 但只要掌握了规律就很好记。
  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

示例:

函数1:execl

l:参数是列表

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

path :路径+目标文件名

arg :参数包,包含了若干个参数

... :可变参数列表(最后一个参数为NULL,标识参数传递完毕)

不创建子进程进行进程替换

示例:

当前未进行程序替换:

[wxq@VM-4-9-centos code_4_10_2]$ cat process_replace.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("\n");
    printf("****************process begin*************\n");

    printf("hello world\n");

    printf("*****************process end**************\n");
    printf("\n");

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ ./test 

****************process begin*************
hello world
*****************process end**************

[wxq@VM-4-9-centos code_4_10_2]$ 

进行程序替换①:

[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ cat process_replace.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("\n");
    printf("****************process begin*************\n");

    execl("/usr/bin/ls", "ls", "-l",NULL);

    printf("hello world\n");

    printf("*****************process end**************\n");
    printf("\n");

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ ./test 

****************process begin*************
total 20
-rw-rw-r-- 1 wxq wxq   69 Apr 10 19:46 Makefile
-rw-rw-r-- 1 wxq wxq  321 Apr 10 20:54 process_replace.c
-rwxrwxr-x 1 wxq wxq 8472 Apr 10 20:54 test
[wxq@VM-4-9-centos code_4_10_2]$ 

进行程序替换②:

[wxq@VM-4-9-centos code_4_10_2]$ cat process_replace.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("\n");
    printf("****************process begin*************\n");

  //  execl("/usr/bin/ls", "ls", "-l",NULL);

    execl("/usr/bin/top", "top",NULL);
    
    printf("hello world\n");

    printf("*****************process end**************\n");
    printf("\n");

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ ./test 

****************process begin*************
top - 20:57:31 up 220 days, 23:12,  3 users,  load average: 0.01, 0.03, 0.05
Tasks: 126 total,   1 running, 120 sleeping,   0 stopped,   5 zombie
%Cpu(s):  0.5 us,  0.3 sy,  0.0 ni, 99.0 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  2046504 total,   152152 free,   279976 used,  1614376 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  1568788 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                 
  473 root      20   0  973744  36212  16904 S   1.3  1.8  11:39.93 YDService                                                                               
20006 root      20   0  757184  17520   2624 S   0.3  0.9 671:00.83 barad_agent                                                                             
    1 root      20   0   43728   3916   2436 S   0.0  0.2  21:57.28 systemd                                                                                 
    2 root      20   0       0      0      0 S   0.0  0.0   0:08.15 kthreadd                                                                                
    4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H                                                                            
    6 root      20   0       0      0      0 S   0.0  0.0   3:17.70 ksoftirqd/0                                                                             
    7 root      rt   0       0      0      0 S   0.0  0.0   1:11.94 migration/0                                                                             
    8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh                                                                                  
    9 root      20   0       0      0      0 S   0.0  0.0  51:58.18 rcu_sched                                                                               
   10 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 lru-add-drain                                                                           
   11 root      rt   0       0      0      0 S   0.0  0.0   0:52.50 watchdog/0                                                                              
   12 root      rt   0       0      0      0 S   0.0  0.0   0:45.59 watchdog/1                                                                              
   13 root      rt   0       0      0      0 S   0.0  0.0   1:11.67 migration/1                                                                             
   14 root      20   0       0      0      0 S   0.0  0.0   2:59.24 ksoftirqd/1                                                                             
   16 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/1:0H                                                                            
   18 root      20   0       0      0      0 S   0.0  0.0   0:00.00 kdevtmpfs                                                                               
   19 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 netns                                                                                   
   20 root      20   0       0      0      0 S   0.0  0.0   0:04.50 khungtaskd                                                                              
   21 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 writeback                                                                               
   22 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kintegrityd                                                                             
   23 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 bioset                                                                                  
   24 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 bioset                                                                                  
   25 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 bioset                                                                                  
[wxq@VM-4-9-centos code_4_10_2]$ 

注意:可变模板参数最后一定要传NULL,不然会导致程序替换失败

这里有一个问题,为什么???这里的内容没有被显示在屏幕上???

  • 其实,这里的命令根本就没有被执行。
  • 原因是execl是程序替换,调用该函数成功之后,会将当前进程的所有代码以及数据都进行替换。包括已经执行的和未执行的!
  • 所以,—旦调用成功,后续的所有代码,都不会执行。
  • execl为什么调用成功,没有返回值呢?(注:失败,返回-1,继续执行原进程的后续代码)
  • execl根本不需要返回值进行判断,可以理解为它在替换的过程中,把自己都干掉了,所以产生的新代码和它没有关系
     

关于替换程序时的写时拷贝

        其实这里还涉及到一个写时拷贝的问题:在之前的博客中提及过,父进程创建子进程,代码是共享的,地址空间也是共享的,因为代码是不能更改的,而数据写时拷贝。那么发生了进程替换,父子进程还是共用一块代码,一个地址空间吗???那不就乱套了吗?所以我们需要捋顺这一观点:

首先:

父进程创建子进程,如果父进程或者子进程对数据进行写入,那么操作系统就会发生写时拷贝。

此时代码不会进行写时拷贝,代码是不可更改的,因为代码存储在常量区,父进程或者子进程只有读取的权限

(此时:代码共享,数据写时拷贝。父子进程共用虚拟地址空间)

其次:

如果子进程发生替换程序,意味着新程序会从磁盘往内存中加载,这不就是写入吗?

此时,代码会不会发生写实拷贝,答案是肯定,因为要保证进程的独立性,此时,父子的代码必须要分离

(此时:代码,数据写时拷贝,重新给子进程建立虚拟地址空间)

fork创建子进程进行替换

  • 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)
  • 子进程往往要调用一种exec函数以执行另一个程序
  • 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动进程开始执行。
  • 调用exec并不创建新进程,所以调用exec前后该进程的id并未改变

示例:

函数1:execl

-----------------------------------------------测试代码process_replace.c (下面的测试代码脚本都是这个)-------------------------------------

[wxq@VM-4-9-centos code_4_10_2]$ cat process_replace.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

int main()
{
    pid_t id = fork();

    if( id == 0 )
    {
        //child process
        printf("子进程开始运行, pid:%d\n", getpid());
        execl("/usr/bin/ls", "ls", "-l", NULL);
        exit(1);
    }
    else
    {
        printf("父进程开始运行, pid:%d\n", getppid());
        int status = 0;
        pid_t ret = waitpid(-1, &status, 0); //-1 :等待任意子进程
        if(ret > 0)
        {
            printf("waitpid success! exit code: %d\n", WEXITSTATUS(status));
        }

    }

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ ./test 
父进程开始运行, pid:16226
子进程开始运行, pid:29294
total 20
-rw-rw-r-- 1 wxq wxq   69 Apr 10 19:46 Makefile
-rw-rw-r-- 1 wxq wxq  985 Apr 10 21:26 process_replace.c
-rwxrwxr-x 1 wxq wxq 8680 Apr 10 21:26 test
waitpid success! exit code: 0

观察输出可以发现,其实父进程或者子进程的运行顺序是由操作系统决定的,但是,父进程一定会等待子进程运行结束。

函数2:execv

v:表示参数是数组   

execv和execl只有传参上的区别

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

图例:

示例:

输入:

     //参数是列表形式      
     // execl("/usr/bin/ls", "ls", "-l", NULL);  
                           
      char* _argv[32] = {(char*)"ls", (char*)"-l", NULL};  
     // 参数的数组形式     
      execv("/usr/bin/ls", _argv);  
                           

输出:

[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ ./test 
父进程开始运行, pid:16226
子进程开始运行, pid:1093
total 20
-rw-rw-r-- 1 wxq wxq   69 Apr 10 19:46 Makefile
-rw-rw-r-- 1 wxq wxq 1127 Apr 10 21:41 process_replace.c
-rwxrwxr-x 1 wxq wxq 8680 Apr 10 21:41 test
waitpid success! exit code: 0

函数3:execlp

p:我会去自己的环境变量PATH中进行查找,你不用告诉我你要执行的程序在哪

补:执行程序需要带路径吗?答案是需要的,但是系统的程序是不需要的的,就是因为环境变量。详细可以参考:Linux的环境变量

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

示例:

输入:

     //参数是列表形式      
     // execl("/usr/bin/ls", "ls", "-l", NULL);  
                           
     // char* _argv[32] = {(char*)"ls", (char*)"-l", NULL};  
     // 参数的数组形式     
     // execv("/usr/bin/ls", _argv);  
                           
      //不需要传入路径                                                                                                                                 
     execlp("ls", "ls", "-a", "-l", NULL); 

输出:

[wxq@VM-4-9-centos code_4_10_2]$ vim process_replace.c 
[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ ./test 
父进程开始运行, pid:16226
子进程开始运行, pid:4772
total 28
drwxrwxr-x 2 wxq wxq 4096 Apr 10 21:55 .
drwxrwxr-x 8 wxq wxq 4096 Apr 10 19:42 ..
-rw-rw-r-- 1 wxq wxq   69 Apr 10 19:46 Makefile
-rw-rw-r-- 1 wxq wxq 1258 Apr 10 21:53 process_replace.c
-rwxrwxr-x 1 wxq wxq 8680 Apr 10 21:55 test
waitpid success! exit code: 0
[wxq@VM-4-9-centos code_4_10_2]$ 

其实这里有个小概念需要明白,p不是代表不需要传入路径吗?那为什么还要:输入 "ls", "ls" ,"-a", "-l" NULL

 你不是告诉我,execlp,p不是表示path,不是说不需要带路径吗?为什么这里还需要写第一个"ls"???

图例:

函数4:execvp

那这个不就是很好理解了嘛,v表示参数是数组,p表示不需要传入路径

  int execvp(const char *file, char *const argv[]);

示例:

输入:

         char* _argv[32] = {(char*)"ls", (char*)"-l", NULL};                                            
                                                                                                        
        //参数是列表形式                                                                                
        // execl("/usr/bin/ls", "ls", "-l", NULL);                                                      
                                                                                                       
        // 参数的数组形式                                                                               
        // execv("/usr/bin/ls", _argv);                                                                 
                                                                                                        
        //不需要传入路径                                                                               
        //execlp("ls", "ls", "-a", "-l", NULL);                                                        
                                                                                                       
         execvp("ls", _argv);

输出:

[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ ./test 
父进程开始运行, pid:16226
子进程开始运行, pid:7646
total 20
-rw-rw-r-- 1 wxq wxq   69 Apr 10 19:46 Makefile
-rw-rw-r-- 1 wxq wxq 1287 Apr 10 22:05 process_replace.c
-rwxrwxr-x 1 wxq wxq 8680 Apr 10 22:06 test
waitpid success! exit code: 0
[wxq@VM-4-9-centos code_4_10_2]$ 

函数5:execle
int execle(const char *path, const char *arg, ..., char * const envp[]);

这个其实是有点上难度的,因为这里的表示的是环境变量

怎么去描述这个函数呢???

咱先描述另外一个东西再来带入到这个函数。

比如说,我们上面执行的都是系统的命令,假如程序替换我想替换一个我自己写的程序行不行呢?

示例:

我们自己写一个程序 mycmd

通过程序  test (process_replace.c) 创建子进程去调用我们自己写的程序mycmd

[wxq@VM-4-9-centos code_4_10_2]$ ll
total 36
-rw-rw-r-- 1 wxq wxq  125 Apr 10 22:25 Makefile
-rwxrwxr-x 1 wxq wxq 8456 Apr 10 22:32 mycmd
-rw-rw-r-- 1 wxq wxq  496 Apr 10 22:32 mycmd.c
-rw-rw-r-- 1 wxq wxq 1287 Apr 10 22:05 process_replace.c
-rwxrwxr-x 1 wxq wxq 8680 Apr 10 22:06 test
[wxq@VM-4-9-centos code_4_10_2]$ cat mycmd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        printf("can not execute!\n");
        exit(-1);
    }
    else if(strcmp(argv[1], "-a") == 0)
    {
        printf("hello a!\n");
    }
    else if(strcmp(argv[1], "-b") == 0)
    {
        printf("hello b!\n");
    }
    else if(strcmp(argv[1], "-c") == 0)
    {
        printf("hello c!\n");
    }
    else
    {
        printf("default!\n");
    }

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ cat process_replace.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

int main()
{
    pid_t id = fork();

    if( id == 0 )
    {
        //child process
        printf("子进程开始运行, pid:%d\n", getpid());

        char* _argv[32] = {(char*)"ls", (char*)"-l", NULL};

       //参数是列表形式
       // execl("/usr/bin/ls", "ls", "-l", NULL);
      
       // 参数的数组形式
       // execv("/usr/bin/ls", _argv);
        
        //不需要传入路径
        //execlp("ls", "ls", "-a", "-l", NULL);

       // execvp("ls", _argv);

        execl("/home/wxq/study_4/code_4_10_2/mycmd", "mycmd", "-a", NULL);
        
        exit(1);
    }
    else
    {
        printf("父进程开始运行, pid:%d\n", getppid());
        int status = 0;
        pid_t ret = waitpid(-1, &status, 0); //-1 :等待任意子进程
        if(ret > 0)
        {
            printf("waitpid success! exit code: %d\n", WEXITSTATUS(status));
        }

    }

    return 0;
}
[wxq@VM-4-9-centos code_4_10_2]$ make
gcc -o test process_replace.c
[wxq@VM-4-9-centos code_4_10_2]$ ./test 
父进程开始运行, pid:16226
子进程开始运行, pid:15842
hello a!
waitpid success! exit code: 0

通过上面的测试,我们可以看到,我们自己写的程序是可以被程序替换,并且成功执行的。

上述逻辑:

ok,现在有了这个基础,我们再来聊一聊execle这个函数

接下来写的东西围绕着(execle函数在进行程序替换的时候,可以把环境变量传递到我们想要执行的程序里面)

意思就是我们在 process_replace.c中设置一个环境变量,然后传递给mycmd,看看mycmd是不是能使用这个环境变量。

第一步:

因为这里我们并没有设置环境变量,也没有传入,所以这里为空

第二步:在 process_replace.c 中添加环境变量,再使用execle进行程序替换

所以函数execle不仅调用了程序mycmd还给mycmd传入了环境变量
 


但是从严格意义上来说,上述关于程序替换的接口并不是操作系统提供给我们的,操作系统提供的接口只有一个:execve

NAME
       execve - execute program

SYNOPSIS
       #include <unistd.h>

       int execve(const char *filename, char *const argv[],
                  char *const envp[]);

这6个接口是经过封装提供给我们的,为的是满足不同的调用场景。底层都是execve这个接口

NAME
       execl, execlp, execle, execv, execvp, execvpe - execute a file

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python-study-day1-(病人管理系统-带sql)

MainWindow代码 from tkinter import * from tkinter import messagebox from tkinter.ttk import Comboboxclass MianWindow(Frame):def __init__(self, masterNone):super().__init__(master, padx30, pady20)self.flag 0self.pack(expandTrue, fillBOTH)self.id StringVa…

vue3:菜单、标签页和面包屑联动效果

文章目录 1.整体思路2.实现过程 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; openAI 的 GPT 大模型的发展历程。 1.整体思路 在之前做的后台项目中&#xff0c;菜单、标签页和面包屑之间的联动&#xff0c;自己都是通过在路由前置守卫中&#xff0c;定义b…

铭飞SQL注入严重信息泄露【附POC】

感谢您抽出 阅读本文 MCMS是一个<完整开源的Java CMS&#xff01;基于SpringBoot 2架构&#xff0c;前端基于vue、element ui。MCMS存在SQL注入漏洞&#xff0c;攻击者可通过该漏洞获取数据库敏感信息等。目前厂商暂未发布修复措施解决此安全问题&#xff0c;建议使用此软件…

配置QtCreator能加载自定义插件的环境

配置对应环境 引言查看当前版本配置能够加载插件的环境 引言 生成的自定义插件能在QtCreator的设计器中加载&#xff0c;需要满足当前使用的QtCreator的编译时所需的Qt库和编译器。 查看当前版本 这里需要先查看自己使用的QtCreator的版本&#xff0c;即生成QtCreator时使用…

【LeetCode】回溯算法类题目详解

所有题目均来自于LeetCode&#xff0c;刷题代码使用的Python3版本 回溯算法 回溯算法是一种搜索的方法&#xff0c;在二叉树总结当中&#xff0c;经常使用到递归去解决相关的问题&#xff0c;在二叉树的所有路径问题中&#xff0c;我们就使用到了回溯算法来找到所有的路径。 …

淘宝1688京东店铺所有商品数据接口(item_search_shop接口系列,可测试)

淘宝、1688和京东都提供了API接口供开发者调用&#xff0c;以获取店铺和商品的详细数据。对于您提到的item_search_shop接口系列&#xff0c;这主要是用于获取店铺所有商品的数据。然而&#xff0c;具体的接口名称和功能可能会因平台而异&#xff0c;且可能随着平台的更新而有所…

LigaAI x 极狐GitLab,共探 AI 时代研发提效新范式

近日&#xff0c;LigaAI 和极狐GitLab 宣布合作&#xff0c;双方将一起探索 AI 时代的研发效能新范式&#xff0c;提供 AI 赋能的一站式研发效能解决方案&#xff0c;让 AI 成为中国程序员和企业发展的新质生产力。 软件研发是一个涉及人员多、流程多、系统多的复杂工程&#…

微服务面试题二

1.什么是雪崩 微服务之间相互调用&#xff0c;因为调用链中的一个服务故障&#xff0c;引起整个链路都无法访问的情况。 如何解决雪崩&#xff1f; 超时处理&#xff1a;请求超时就返回错误信息&#xff0c;不会无休止等待仓壁模式&#xff1a;限定每个业务能使用的线程数&a…

cordova后台插件开发新手教程

typora-root-url: imags cordova后台插件开发新手教程 预安装环境&#xff1a;JDK11、Android studios、nodo.js 一、环境搭建 1.安装Cordova npm install -g cordova2.创建项目 cordova create 具体命令&#xff1a; cordova create 目录名 包名 项目名 执行结果终端&am…

大模型RAG(三)检索环节(Retriever)

1. 搜索索引 &#xff08;1&#xff09;向量存储索引 最原始的实现是使用平面索引 — 查询向量和所有块向量之间的暴力计算距离。根据索引选择、数据和搜索需求&#xff0c;还可以存储元数据&#xff0c;并使用元数据过滤器来按照日期或来源等条件进行信息检索。LlamaIndex 支…

【实战JVM】打破双亲委派机制之线程上下文类加载器

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

CS与MSF联动/shell互相反弹

Cs的shell反弹到msf 参考资料:https://blog.csdn.net/Zlirving_/article/details/113862910 先建立监听器 先建立一个监听器&#xff0c;和msf的要一一对应&#xff0c;上面的ip必须是可以ping通的大部分情况是外网ip Msf&#xff1a; use exploit/multi/handler set paylo…

Netty学习——实战篇1 BIO、NIO入门demo 备注

1 BIO 实战代码 Slf4j public class BIOServer {public static void main(String[] args) throws IOException {//1 创建线程池ExecutorService threadPool Executors.newCachedThreadPool();//2 创建ServerSocketServerSocket serverSocket new ServerSocket(8000);log.in…

高清无水印短视频素材去哪找?今天讲五个素材网站,记得收藏

在视频剪辑的世界里&#xff0c;我就像是那个经常带着一副老花镜在宝藏地图上寻宝的老海盗。每次寻宝之旅&#xff0c;我都能从九才素材网这个家门口的宝藏开始&#xff0c;然后驾驶我的老旧剪辑船&#xff0c;航向国际的深蓝大海&#xff0c;寻找那些只属于知情者的秘密宝藏。…

【C++进阶】C++异常详解

C异常 一&#xff0c;传统处理错误方式二&#xff0c;C处理的方式三&#xff0c;异常的概念四&#xff0c;异常的使用4.1 异常和捕获的匹配原则4.2 函数调用链中异常栈展开匹配原则4.3 异常的重新抛出&#xff08;异常安全问题&#xff09;4.4 RAII思想在异常中的作用 五&#…

使用Java+Maven+TestNG进行自动化测试

写作背景&#xff1a;有点Java基础的功能测试人员&#xff08;点点点工程师&#xff09;&#xff0c;所在项目有"去QE"的趋势&#xff0c;所以自己要多点亮其他技能&#xff0c;让路子走宽点。 简单说一下去QE&#xff1a;项目测试不再有专职的测试工程师来做&#x…

计算机网络——40各个层次的安全性

各个层次的安全性 安全电子邮件 Alice需要发送机密的报文m给Bob Alice 产生随机的对称秘钥&#xff0c; K s K_s Ks​使用 K s K_s Ks​对报文进行加密&#xff08;为了效率&#xff09;对 K s K_s Ks​使用Bob的公钥进行加密发送 K s ( m ) K_s(m) Ks​(m)和 K B ( K S ) K…

小程序/app/H5多端圈子社区论坛系统交友/社交/陌生人社交即时聊天私域话题社区论坛 行业圈子小程序 微信社区小程序圈子论坛社区小程序

项目介绍 这是一个社区论坛类小程序项目源码&#xff0c;可以实现用户发送自定义图文内容&#xff0c;点赞&#xff0c;评论&#xff0c;回复&#xff0c;记录评论过的帖子&#xff0c;记录发表过的帖子&#xff0c;左滑删除&#xff0c;在线实时接收消息&#xff0c;离线接收…

MySQL高级篇(索引概述、优缺点、结构 B+Tree)

目录 1、索引概述 2、索引优缺点 3、索引的结构 1、索引概述 介绍&#xff1a;索引&#xff08;index&#xff09;是帮助MySQL 高效获取数据 的 数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数…

分布式系统:缓存与数据库一致性问题

前言 缓存设计是应用系统设计中重要的一环&#xff0c;是通过空间换取时间的一种策略&#xff0c;达到高性能访问数据的目的&#xff1b;但是缓存的数据并不是时刻存在内存中&#xff0c;当数据发生变化时&#xff0c;如何与数据库中的数据保持一致&#xff0c;以满足业务系统…