【Linux系统编程】:system V共享内存

news2025/1/15 21:48:45

前言(System V简介)

System V是一种强大的进程管理系统,在UNIX和类UNIX操作系统中广泛应用。
它主要包含进程控制块(PCB)、进程表、信号集、文件描述符表等部分。其中,进程控制块是System V中的核心数据结构,包含了进程的所有信息。
System V提供了三种进程间通信的标准:System V消息队列、System V共享内存和System V信号量。这些标准使得System V在进程间通信方面具有很高的灵活性和效率。

1.System V共享内存的原理

让进程通信的前提就是让进程能够访问同一份资源,而共享内存,本质就是操作系统在内存中开辟一块空间,通过某种机制(如页表)映射到进程虚拟空间的共享区中,从而使多个进程可以像访问自己的私有内存一样访问这块共享内存区域,实现进程间的数据共享,即进程通信。
共享内存区是最快的IPC(Inter-Process Communication)形式。一旦物理内存映射到共享它的进程的地址空间中,这些进程间的数据通信不需要通过进入系统内核来实现。
在这里插入图片描述
当物理内存映射到共享区后,进程就可以通过访问共享区中的“共享内存”进行通信,在这里插入图片描述

2.共享内存函数

2.1 shmget()创建共享内存

shmget() 是一个在 Unix-like 操作系统中用于创建或访问共享内存段的系统调用函数。它是 System V IPC(进程间通信)机制的一部分,允许不同进程共享同一块内存区域,从而实现进程间的数据交换。
在这里插入图片描述
https://man.cx/shmget

参数说明

  • key:这是一个键值,用于标识共享内存段。通常,这个键是通过 ftok() 函数生成的。在这里插入图片描述
    https://man.cx/ftok
  • size:指定共享内存段的大小(以字节为单位)。
  • shmflg:是一组标志位,用于控制共享内存段的创建和访问权限。这个参数可以包含以下值:
    • IPC_CREAT:如果指定的共享内存段不存在,则创建它。
    • IPC_EXCL:与 IPC_CREAT 一起使用,如果共享内存段已经存在,则调用失败。
    • 权限标志(如 0666):设置共享内存段的访问权限,类似于文件系统的权限设置。

返回值

成功时,shmget() 返回一个非负整数,即共享内存段的标识符(shm_id)。
失败时,返回 -1,并设置 errno 以指示错误类型。

ftok()的返回值和shmget的返回值区别

  • 含义不同:
    • ftok()的返回值是一个键值,用于标识特定的IPC资源(如消息队列、共享内存等);
    • 而shmget()的返回值是一个共享内存标识符,用于标识和管理特定的共享内存段。
  • 用途不同:
    • ftok()的返回值通常作为shmget()等函数的参数使用,以指定要操作的IPC资源(给操作系统在内核中使用);
    • 而shmget()的返回值则用于后续的共享内存操作函数中(在用户层给进程使用,共享内存的用户层标识的唯一值),如shmat()(将共享内存连接到进程地址空间)、shmdt(将共享内存从进程地址空间分离)和shmctl(控制共享内存段,如删除它)。

代码练习

comm.hpp:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include "log.hpp"

using namespace std;

const int sm_size = 4096; // 共享内存的大小
const string pathname = "/home/yaols";
const int proj_id = 0x6666;
Log log;

key_t GetKey()
{
    key_t k = ftok(pathname.c_str(), proj_id);
    if (k < 0)
    {
        log(Fatal, "ftok error:%s\n", strerror(errno));
        exit(1);
    }
    log(Info, "ftok success,key is %d\n", k); // key_t类型是对int的封装
    return k;
}
int GetShareMem()
{
    key_t k = GetKey();
    int shmid = shmget(k, sm_size, IPC_CREAT | IPC_EXCL);
    if (shmid < 0)
    {
        log(Fatal, "create share memory error: %s", strerror(errno));
        exit(2);
    }
    log(Info, "create share memory success, shmid: %d", shmid);
    return shmid;
}

processA.cc

#include "comm.hpp"
int main()
{
    int shmid = GetShareMem();
    return 0;
}

当我们多次执行processA,发现shmget()创建的共享内存段不会随着进程的退出而销毁,而是一直存在。

在这里插入图片描述
我们可以用“ipcs -m"指令查看使用共享内存进行进程间通信的信息。在这里插入图片描述
其中1711407108对应的十六进制就是0x66020004。这说明共享内存的生命周期是随内核的。即使所有访问共享内存区域对象的进程都已经正常结束,共享内存区域对象仍然在内核中存在(除非内核重启或者用户释放)。
我们可以用”ipcrm -m shmid"释放对应的共享内存段,在这里插入图片描述
我们将key的输出格式改成16进制,在这里插入图片描述
并设置共享内存段的权限,在这里插入图片描述
再编译运行,在这里插入图片描述

2.2 shmat()挂接共享内存段

shmat() 是一个在类Unix操作系统中用于将共享内存段附加到进程的地址空间的系统调用。它是System V共享内存机制的一部分。shmat() 的全称是 “shared memory attach”,即共享内存附加。通过这个函数,一个进程可以访问由另一个进程通过 shmget() 创建的共享内存段。
https://man.cx/shmat

函数原型

在C语言中,shmat() 的函数原型通常如下:

#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数说明

  • shmid:共享内存标识符,由 shmget() 返回。
  • shmaddr:指定共享内存附加到进程地址空间的起始地址。如果设置为NULL,系统会选择一个合适的地址。
  • shmflg:标志参数,用于控制附加行为。常用的标志包括 SHM_RDONLY(以只读方式附加)和 0(以读写方式附加)。也可以指定 SHM_EXEC(用于执行共享内存段中的代码)和 SHM_RDONLY | SHM_EXEC(以只读和执行权限附加)。

返回值

成功时,shmat() 返回一个指向共享内存段在调用进程地址空间中的起始地址的指针。如果失败,返回 (void *) -1,并设置 errno 以指示错误原因。

错误处理

常见的错误包括:

  • EINVAL:无效的 shmidshmaddrshmflg 组合无效。
  • EACCES:权限不足,尝试以写方式附加只读共享内存段。
  • ENOMEM:没有足够的内存附加共享内存段。

引用:https://yiyan.baidu.com/chat/MzQ3Mzk2NDQ1Nzo0NzM3MTQ3MjA5

代码样例

comm.hpp:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include "log.hpp"

using namespace std;

const int sm_size = 4096; 
// 共享内存的大小,一般建议是4096(4k)的整数倍
//若设定为4097,操作系统实际给的是4096*2字节,但用户只能使用4097
const string pathname = "/home/yaols";
const int proj_id = 0x6666;
Log log;

key_t GetKey()
{
    key_t k = ftok(pathname.c_str(), proj_id);
    if (k < 0)
    {
        log(Fatal, "ftok error:%s\n", strerror(errno));
        exit(1);
    }
    log(Info, "ftok success,key is 0x%x\n", k); // key_t类型是对int的封装
    return k;
}
int GetShareMemHelper(int flag)
{
    key_t k = GetKey();
    int shmid = shmget(k, sm_size, flag);
    if (shmid < 0)
    {
        log(Fatal, "create share memory error: %s", strerror(errno));
        exit(2);
    }
    log(Info, "create share memory success, shmid: %d", shmid);
    return shmid;
}

int CreateShm()//创建共享内存
{
    return GetShareMemHelper(IPC_CREAT | IPC_EXCL | 0666);
}
int GetShm()//获取共享内存
{
    return GetShareMemHelper(IPC_CREAT);
}

processA.cc:

#include "comm.hpp"

int main()
{
    sleep(3);
    
    int shmid = CreateShm();
    log(Debug,"create shm done\n");

    sleep(5);

    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    log(Debug,"attach shm done");

    sleep(5);

    return 0;
}

编译并运行,查看对应共享内存段nattch值的变化,在这里插入图片描述
nattch值表示当前附加到该共享内存段的进程数量,即有多少个进程正在使用该共享内存段。
上面的共享内存段“去关联”是通过“进程退出”,还有没有其他方法“去关联”呢?

2.3 shmdt()分离共享内存段

在 System V 共享内存机制中,shmdt() 函数用于将之前通过 shmat() 函数连接到当前进程地址空间的共享内存段分离(detach)出去。

#include <sys/shm.h>
int shmdt(const void *shmaddr);

参数

  • shmaddr:这是一个指向共享内存段在进程地址空间中起始地址的指针。这个地址应该是之前通过 shmat() 函数成功连接共享内存段时返回的。

返回值

  • 成功时,shmdt() 返回 0。
  • 失败时,返回 -1,并设置 errno 以指示错误类型。

功能

  • shmdt() 函数将指定的共享内存段从调用进程的地址空间中分离。这并不意味着共享内存段被销毁或删除;它只是不再被该进程所访问。
  • 在进程终止或调用 exec() 系列函数之一时,所有附加到该进程的共享内存段都会自动分离。但是,显式调用 shmdt() 是一个好习惯,因为它可以释放与共享内存段关联的资源,并避免潜在的内存泄漏。
  • 重要的是要注意,即使所有进程都调用了 shmdt(),共享内存段也不会被销毁,除非显式地调用 ipcrm 命令或 shmctl() 函数与 IPC_RMID 命令来删除它。
    代码样例
#include "comm.hpp"

int main()
{
    sleep(3);

    int shmid = CreateShm();
    log(Debug,"create shm done\n");

    sleep(5);

    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    log(Debug,"attach shm done,shmaddr 0x%x",shmaddr);

    sleep(5);

    shmdt(shmaddr);
    log(Debug,"detach shm done,shmaddr 0x%x",shmaddr);

    return 0;
}

2.4 shmctl()控制共享内存段

shmctl() 是一个在 Unix-like 操作系统中用于控制共享内存段的系统调用函数。它是 POSIX 标准的一部分,主要用于对由 shmget() 创建或获取的共享内存段执行各种控制操作。这个函数在进程间通信(IPC)中非常重要,特别是在需要共享数据的场景中。
https://man.cx/shmctl

函数原型

#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数

  • shmid:这是由 shmget() 返回的共享内存标识符。
  • cmd:这是一个控制命令,指定了要对共享内存执行的操作。常见的命令包括:
    • IPC_STAT:获取共享内存段的状态,并将结果存储在 buf 中。
    • IPC_SET:设置共享内存段的某些属性(如权限),这些属性由 buf 提供。
    • IPC_RMID:从系统中删除共享内存段,buf为nullptr。
    • SHM_LOCKSHM_UNLOCK:锁定或解锁共享内存段,以防止它被交换到磁盘上(在某些系统上可能不支持)。
  • buf:指向一个 shmid_ds 结构的指针,该结构包含了共享内存段的状态信息或要设置的属性。这个参数在 cmdIPC_STAT 时用于接收信息,在 cmdIPC_SET 时用于提供信息。

返回值

成功时,shmctl() 返回 0。失败时,返回 -1 并设置 errno 以指示错误。

代码示例

comm.hpp文件不变。
processA.cc:

#include "comm.hpp"

int main()
{
    sleep(1);
    int shmid = CreateShm();
    log(Debug,"create shm done\n");

    sleep(1);
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    log(Debug,"attach shm done,shmaddr 0x%x",shmaddr);

    sleep(1);
    shmdt(shmaddr);
    log(Debug,"detach shm done,shmaddr 0x%x",shmaddr);

    sleep(1);
    shmctl(shmid,IPC_RMID,nullptr);
    log(Debug,"destroy shm done,shmaddr 0x%x",shmaddr);

    sleep(1);
    return 0;
}

运行结果:在这里插入图片描述

3.通信代码示例

comm.hpp同上,
processA:

#include "comm.hpp"

int main()
{
    int shmid = CreateShm();
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    //在关联后和分离前通信
    while(true)
    {
        //直接访问共享内存
        cout << "processB say@" << shmaddr << endl;
        sleep(1);
    }
    shmdt(shmaddr);
    shmctl(shmid,IPC_RMID,nullptr);

    return 0;
}

processB:

#include "comm.hpp"

int main()
{
    int shmid = GetShm();
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    //在关联后和分离前通信
    while(true)
    {
        cout << "please Enter@:";
        fgets(shmaddr,4096,stdin);
    }
    shmdt(shmaddr);
    //当进程成功关联某个共享内存段后,可以将该共享内存段当做自己的内存空间使用。
    return 0;
}

运行结果如下:在这里插入图片描述

4.共享内存的特性和属性

4.1特性

  • 共享内存没有同步与互斥之类的保护机制。
  • 共享内存是最快的进程通信方式。
  • 共享内存中的数据需要用户自己维护。

4.2 属性

我们可以通过shmctl()的第三个参数struct shmid_ds *buf,了解共享内存的属性,
https://man.cx/shmctl
在这里插入图片描述其中struct ipc_perm shm_perm最重要,
在这里插入图片描述
我们可以打印一下共享内存的属性,修改一下processA.cc:

#include "comm.hpp"

int main()
{
    int shmid = CreateShm();
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    //在关联后和分离前通信
    struct shmid_ds shmds;
    while(true)
    {
        //直接访问共享内存
        cout << "processB say@" << shmaddr << endl;
        sleep(1);
        
        //获取共享内存的属性
        shmctl(shmid, IPC_STAT, &shmds);
        cout << "shm size: " << shmds.shm_segsz << endl;
        cout << "shm nattch: " << shmds.shm_nattch << endl;
        printf("shm key: 0x%x\n",  shmds.shm_perm.__key);
        //cout << "shm mode: " << shmds.shm_perm.mode << endl;
    }
    shmdt(shmaddr);
    shmctl(shmid,IPC_RMID,nullptr);

    return 0;
}

重新编译并运行,
在这里插入图片描述

共享内存没有同步与互斥机制,我们可以利用管道的同步与互斥对共享内存进行管理。
上面的processA向共享内存中写入数据,processB从共享内存中读取数据,我们可以利用管道文件的特性“读端的open会阻塞等待写端的open打开”,在processA中创建一个管道文件,并通过读方式打开,并根据读到的内容判断是否要执行共享内存的相关操作;在processB中通过写方式打开管道文件,并向管道中写入内容控制共享内存的相关操作。
我们在comm.hpp后添加管道文件的类,

#include <sys/stat.h>
#define FIFO_FILE "./myfifo"
#define MODE 0664
enum
{
    FIFO_CREATE_ERR = 1,
    FIFO_DELETE_ERR,
    FIFO_OPEN_ERR
};
class Init
{
public:
    Init()
    {
        // 创建管道
        int n = mkfifo(FIFO_FILE, MODE);
        if (n == -1)
        {
            perror("mkfifo");
            exit(FIFO_CREATE_ERR);
        }
    }
    ~Init()
    {
        int m = unlink(FIFO_FILE);
        if (m == -1)
        {
            perror("unlink");
            exit(FIFO_DELETE_ERR);
        }
    }
};

processA.cc:

#include "comm.hpp"

int main()
{
    int shmid = CreateShm();
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    //在关联后和分离前通信
    struct shmid_ds shmds;

    Init init;//实例化管理管道文件的类
    int fd = open(FIFO_FILE, O_RDONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!
    if (fd < 0)
    {
        log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);
        exit(FIFO_OPEN_ERR);
    }

    while(true)
    {
        //读取命名 管道的内容
        char c;
        ssize_t s = read(fd, &c, 1);
        if(s == 0) break;
        else if(s < 0) break;

        //直接访问共享内存
        cout << "processB say@" << shmaddr << endl;
        sleep(1);
        
        //获取共享内存的属性
        // shmctl(shmid, IPC_STAT, &shmds);
        // cout << "shm size: " << shmds.shm_segsz << endl;
        // cout << "shm nattch: " << shmds.shm_nattch << endl;
        // printf("shm key: 0x%x\n",  shmds.shm_perm.__key);
        //cout << "shm mode: " << shmds.shm_perm.mode << endl;
    }
    shmdt(shmaddr);
    shmctl(shmid,IPC_RMID,nullptr);
    close(fd);
    return 0;
}

processB.cc:

#include "comm.hpp"

int main()
{
    int shmid = GetShm();
    char *shmaddr = (char*)shmat(shmid,nullptr,0);
    
    int fd = open(FIFO_FILE, O_WRONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!
    if (fd < 0)
    {
        log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);
        exit(FIFO_OPEN_ERR);
    }

    //在关联后和分离前通信
    while(true)
    {
        cout << "please Enter@:";
        fgets(shmaddr,4096,stdin);
        write(fd, "c", 1); // 通知对方     
     }
    shmdt(shmaddr);
    //当进程成功关联某个共享内存段后,可以将该共享内存段当做自己的内存空间使用。
    close(fd);
    return 0;
}

在这里插入图片描述
这样我们只要Ctrl+C掉进程B,进程A因读到的字节数是0,就会退出循环,后续的shmctl()会正常执行。
有同学可能会问,既然我们建立好管道,为什么还要创建共享内存进行通信呢?当我们要传输比较大的数据时,比如1GB,可以用管道进行提醒告诉共享内存准备通信,这样安全效率又相对较高。

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

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

相关文章

[免费]SpringBoot+Vue疫苗接种预约管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue疫苗接种预约管理系统&#xff0c;分享下哈。 项目介绍 如今的时代&#xff0c;是有史以来最好的时代&#xff0c;随着计算机的发展到现在的移动终端的发展&#xff0c;国内目前信息技术已经在…

ROS1切换到ROS2环境

ROS_DISTRO was set to humble before. Please make sure that the environment does not mix paths from different distributions. 这个提示表明在运行 source ~/ros/noetic/setup.bash 之前&#xff0c;环境变量 ROS_DISTRO 已经被设置为 humble。这意味着你可能已经在一个不…

泷羽Sec学习笔记-zmap搭建炮台

zmap搭建炮台 zmap扫描环境&#xff1a;kali-linux 先更新软件库 sudo apt update 下载zmap sudo apt install zmap 开始扫描(需要root权限) sudo zmap -p 80 -o raw_ips.txt 代码解析&#xff1a; sudo&#xff1a;以超级用户&#xff08;管理员&#xff09;权限运行…

Node-red 网络温湿度计

文章目录 前言一、温度数采集二、Node-red流程1.串口2.数据解析3.设置Dashboard3.流程图 三、效果展示 前言 本文使用SHT40温湿度模块、ESP32S3实现温湿度数据采集&#xff0c;通过串口发送给计算机&#xff0c;使用Node-red Dashboard进行展示&#xff0c;可以在局域网任意计…

程序算术题-2

程序算术题-2 输出所有组合逻辑实例代码 输出所有排列逻辑实例代码 输出所有组合 计算一组数字按n位数组合的所有组合。 逻辑 /*** param stringBuilder 用于组合的拼接* param list 组合数序列* param level 目前位数* param exceptedLevel 组合期待位数*/…

mac删除程序坞(Dock)中“无法打开的程序“

参考&#xff1a; Mac删除软件之后图标还在怎么办&#xff1f;https://blog.csdn.net/weixin_46500474/article/details/124284161Mac程序坞中软件删除出现残留“&#xff1f;”图标无法删除解决方法&#xff1a; https://blog.csdn.net/shenwenhao1990/article/details/12865…

Simdroid-EC:液冷仿真新星,助力新能源汽车电机控制器高效散热

近年来&#xff0c;新能源电动车的销量呈现出快速增长的态势。据统计&#xff0c;2024 年1-10月中国新能源汽车销量达728万辆&#xff0c;同比增长37.8%。 电机控制器在新能源汽车中对于保障动力和安全性能扮演着至关重要的角色&#xff0c;其核心部件IGBT&#xff08;绝缘栅双…

使用 ESP32 构建倒车雷达系统:蜂鸣器警报功能详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;趣享先生的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&…

【数据结构】堆的概念、结构、模拟实现以及应用

本篇我们来介绍一下数据结构中的堆。 1.堆的概念及结构 1&#xff09;堆是一颗完全二叉树。 2&#xff09;堆又分为大堆和小堆&#xff0c;大堆就是树里面任何一个父节点都大于子节点&#xff0c;所以根节点是最大值&#xff1b;小堆就是树里面任何一个父节点都小于子节点&am…

MySQL(五)--- 事务

1、CURD操作不加控制时,可能会出现什么问题 即:类似于线程安全问题,可能会导致数据不一致问题。 因为,MySQL内部本身就是多线程服务。 1.1、CURD满足什么属性时,才能避免上述问题 1、买票的过程得是原子的吧。 2、买票互相应该不能影响吧。 3、买完票应该要永久有效吧。…

UE5中的自定义 Object Channel 和 Trace Channel

在 UE5&#xff08;Unreal Engine 5&#xff09; 中&#xff0c;项目设置中的 自定义 Object Channel 和 Trace Channel 主要用于管理物体和射线的碰撞检测行为。这两者是为 碰撞系统 和 物理模拟 提供定制化设置的工具。 1. Object Channel&#xff08;物体通道&#xff09; …

【AI+网络/仿真数据集】1分钟搭建云原生端到端5G网络

导语&#xff1a; 近期智慧网络开放创新平台上线了端到端网络仿真能力&#xff0c;区别于传统的网络仿真工具需要复杂的领域知识可界面操作&#xff0c;该平台的网络仿真能力主打一个小白友好和功能专业。 https://jiutian.10086.cn/open/​jiutian.10086.cn/open/ 端到端仿…

mybatisplus如何自定义xml文件-源码下载

1、问题概述&#xff1f; MybatisPlus通过BaseMapper为我们带来了丰富的基础功能操作&#xff0c;非常使用。 但是在实际的操作中&#xff0c;我们还需要大量的自定义SQL的的时候&#xff0c;这时候就需要自定义xml&#xff0c;从而自定义sql语句。 2、创建工程 2.1、项目结…

经纬度坐标系转换:全面解析与实践

摘要 在地理信息处理与地图应用开发领域&#xff0c;经纬度坐标系的转换起着举足轻重的作用。不同的地图服务提供商&#xff0c;如百度和高德&#xff0c;各自采用了特定的坐标系&#xff0c;并且在某些情况下需要进行相互转换以及与其他通用坐标系之间的转换。本文将深入探讨…

Qt之第三方库‌QXlsx使用(三)

Qt开发 系列文章 - QXlsx&#xff08;三&#xff09; 目录 前言 一、Qt开源库 二、QXlsx 1.QXlsx介绍 2.QXlsx下载 3.QXlsx移植 4.修改项目文件.pro 三、使用技巧 1.添加头文件 2.写入数据 3.读出数据 总结 前言 Qt第三方控件库是指非Qt官方提供的、用于扩展Qt应用…

C++类的运算符重载

目标 让自定义的类直接使用运算符运算 代码 头文件及类定义 #include <iostream>using namespace std; class Complex {int rel;int vir; public:void show(){cout <<"("<<this->rel<<","<<this->vir<<&quo…

SQL注入--Sqlmap使用

一.GET型注入 介绍&#xff1a;注入点在URL里的称之为GET型注入。 单目标 sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id1" sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id1&page10" -p page sqlmap.py -u "http://127.0.0.1/sqli/Less-…

前端编辑器JSON HTML等,vue2-ace-editor,vue3-ace-editor

与框架无关 vue2-ace-editor有问题&#xff0c;ace拿不到&#xff08;brace&#xff09; 一些组件都是基于ace-builds或者brace包装的 不如直接用下面的&#xff0c;不如直接使用下面的 <template><div ref"editor" class"json-editor"><…

知行之桥EDI系统V2024 12月9111版本更新

知行之桥EDI系统V2024于12月推出版本更新&#xff08;版本号&#xff1a;9111&#xff09;&#xff0c;在原有产品的基础上进行了一系列的新增、更改和修复&#xff0c;以确保 EDI 和 MFT 集成尽可能的简单化。 主要特性 新增 新增EDI 交易伙伴管理控制台 交易伙伴管理控制台…

nmap详解

Nmap&#xff08;Network Mapper&#xff09;是一个开放源代码的网络探测和安全审核的工具。由于它的功能强大&#xff0c;被广泛应用于网络安全领域。以下是Nmap的一些主要功能及其在实战中的应用举例。 Nmap的主要功能&#xff1a; 端口扫描&#xff1a;检测目标主机上开放…