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

【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)

 9efbcbc3d25747719da38c01b3fa9b4f.gif

                                                      作者主页:     作者主页

                                                      本篇博客专栏:Linux

                                                      创作时间 :2024年11月2日

9efbcbc3d25747719da38c01b3fa9b4f.gif

命名管道:

  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
  • 命名管道是一种特殊类型的文件 

我们可以使用mkfifo命令来创建一个管道。

然后通过echo往里面写入一段内容:

回车之后管道不会关闭,在终端2查看可以发现他的内存大小仍然是0,当我们在管道2打印出内容后,管道就自动关闭了

当我们这样执行的时候,我们就可以发现在一直不停的打印我们输入到管道的内容

下面我们在程序里面建立一个管道:

 返回值为0是成功,不为0就是失败。

下面是一个运用命名管道进行通信的例子:

Pipe.hpp:(这里是一些的共享的资源,包括路径,打开管道,关闭管道)

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;const string gpathname = "./myfifo";
const mode_t gmode = 0600;
const int gdefault = -1;
const int gsize = 1024;
const int gForWrite = O_WRONLY;
const int gForRead = O_RDONLY;int OpenPipe(int flag){int _fd = ::open(gpathname.c_str(), flag);if (_fd == -1){std::cerr << "open errno" << std::endl;return _fd;}return _fd;}void ClosePipeHelper(int fd){if (fd >= 0)::close(fd);}// class NamePipe
// {
// private:// public:// };// int CreateNamePipe(string pathname)
// {
//     umask(0);
//     int n = mkfifo(pathname.c_str(), 0600);
//     if (n != 0)
//     {
//         std::cerr << "mkfifo errno" << std::endl;
//         return -1;
//     }
//     return n;
// }// class NamePipe
// {
// public:
//     NamePipe()
//     {
//     }
//     ~NamePipe()
//     {
//     }// private:
//     const string fifo_path;
//     int _id;
//     int _fd;
// };

Server.hpp及Server.cc

#include "Pipe.hpp"class Init
{
public:Init(){umask(0);int n = ::mkfifo(gpathname.c_str(), gmode);if (n < 0){std::cerr << "mkfifo errno" << std::endl;return;}std::cout << "mkfifo success" << std::endl;}~Init(){int n = ::unlink(gpathname.c_str());if (n != 0){std::cerr << "unlink failed" << std::endl;}std::cout << "unlink success" << std::endl;}private:
};Init init;class Server
{
public:Server() : _fd(gdefault){}bool OpenPipeForRead(){_fd = OpenPipe(gForRead);if (_fd < 0){std::cerr << "Open cerrno" << std::endl;return false;}return true;}int RecvPipe(std::string *out){char buffer[gsize];ssize_t n = ::read(_fd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;*out = buffer;}return n;}void ClosePipe(){ClosePipeHelper(_fd);}~Server(){}private:int _fd;
};
#include "Server.hpp"int main()
{Server s;// 打开管道s.OpenPipeForRead();string message;while (1){if (s.RecvPipe(&message) > 0){std::cout << "Client Say:" << message << std::endl;}else{break;}}std::cout << "Client quit,me too" << std::endl;// 关闭管道s.ClosePipe();return 0;
}

Client.hpp及Client.cc

#include "Pipe.hpp"class Client
{
public:Client() : _fd(gdefault){}bool OpenPipeForWrite(){_fd = OpenPipe(gForWrite);if (_fd < 0)return false;return true;}int SendPipe(const std::string &in){return ::write(_fd, in.c_str(), in.size());}void ClosePipe(){if (_fd >= 0){::close(_fd);}}~Client(){}private:int _fd;
};
#include "Client.hpp"int main()
{Client c;c.OpenPipeForWrite();while (1){std::string message;std::cout << "Client Enter:" << std::endl;std::getline(std::cin, message);c.SendPipe(message);}c.ClosePipe();return 0;
}

system V共享内存

 system V IPC是一种本地通信方案。共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据

共享内存在系统中可以同时存在多份,供不同对进程进行通信。

共享内存不是简单的一段内存空间,它也要有描述并管理共享内存的数据结构和匹配算法。

共享内存函数 

shmget 函数

该函数是系统调用,操作系统提供系统调用,让我们创建共享内存。

功能:用来创建共享内存 

参数:

key:这个共享内存段名字(由用户形成)

size:共享内存大小

shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的

常见标志位组合和使用:

IPC_CREAT  、IPC_EXCL

IPC_CREAT:如果你要创建的共享内存不存在,就创建。如果存在,就获取该共享内存并返回。
IPC_EXCL:单独使用没意义,只有和IPC_CREAT组合才有意义
IPC_CREAT | IPC_EXCL:如果你要创建的共享内存不存在,就创建。如果存在,就出错返回。(如果成功返回,意味着这shm是全新的)
key,用来标志共享内存,可以让进程a和b找到共享内存。

系统提供了随机生成key值的方法ftok

返回值:成功则返回共享内存段的标识码;失败返回-1

ftok函数:

 ftok不是系统调用,通过我们提供路径和id(这两个值可以随便写)帮我们生成一个key值。我们给a、b两个进程提供同样的路径和id,调用ftok,就能形成同样的key,就能看到同一个共享内存了。

返回值:成功了就返回key值,失败就返回-1。

 共享内存的释放

 共享内存不随着进程的结束而自动释放,需要我们手动释放(指令或者其他系统调用),否则会一直存在,直到系统重启。

共享内存的生命周期随内核,文件的生命周期随进程。

我们可以通过指令ipcs -m 来查看共享内存

可以通过ipsrm -m shmid(自己得到)来释放共享内存

若不想通过指令释放,可以通过下面这个函数释放

 shmctl 函数

shmid:由shmget返回的共享内存标识码

cmd:将要采取的动作(有三个可取值,如下图)

buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

传IPC_STAT可以获取共享内存的属性,传IPC_RMID可以删除共享内存。

key和shmid的比较

key:属于用户形成,内核使用的一个字段,用户不能用key来进行shm的管理。它是内核用来进行区分shm的唯一性的。

shmid:内核给用户返回的一个标识符,用来进行用户级对共享内存进行管理的id值。

shmat 函数 

功能:将共享内存段连接到进程地址空间。

如果未来不想使用该共享内存,可以用shmdt去关联

 参数

shmid: 共享内存标识

shmaddr:指定共享内存想挂接到哪个地址上 

shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

返回值:成功返回共享内存的起始地址;失败返回-1

shmdt 函数

功能:将共享内存段与当前进程脱离

参数

shmaddr: 由shmat所返回的指针

返回值:成功返回0;失败返回-1

注意:将共享内存段与当前进程脱离不等于删除共享内存段

接口使用例子

Client.cc

#include "Shm.hpp"
#include "namedPipe.hpp"int main()
{// 1. 创建共享内存Shm shm(gpathname, gproj_id, gUser);shm.Zero();char *shmaddr = (char *)shm.Addr();sleep(3);// 2. 打开管道NamePiped fifo(comm_path, User);fifo.OpenForWrite();// 当成stringchar ch = 'A';while (ch <= 'Z'){shmaddr[ch - 'A'] = ch;std::string temp = "wakeup";std::cout << "add " << ch << " into Shm, " << "wakeup reader" << std::endl;fifo.WriteNamedPipe(temp);sleep(2);ch++;}return 0;
}

Server.cc

#include "Shm.hpp"
#include "namedPipe.hpp"int main()
{// 1. 创建共享内存Shm shm(gpathname, gproj_id, gCreater);char *shmaddr = (char*)shm.Addr();shm.DebugShm();// 2. 创建管道NamePiped fifo(comm_path, Creater);fifo.OpenForRead();while(true){std::string temp;fifo.ReadNamedPipe(&temp);std::cout << "shm memory content: " << shmaddr << std::endl;}sleep(5);return 0;
}

Shm.hpp

#ifndef __SHM_HPP__
#define __SHM_HPP__#include <iostream>
#include <string>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/home/whb/code/111/code/lesson22/4.shm";
const int gproj_id = 0x66;
const int gShmSize = 4097; // 4096*nclass Shm
{
private:key_t GetCommKey(){key_t k = ftok(_pathname.c_str(), _proj_id);if (k < 0){perror("ftok");}return k;}int GetShmHelper(key_t key, int size, int flag){int shmid = shmget(key, size, flag);if (shmid < 0){perror("shmget");}return shmid;}std::string RoleToString(int who){if (who == gCreater)return "Creater";else if (who == gUser)return "gUser";elsereturn "None";}void *AttachShm(){if (_addrshm != nullptr)DetachShm(_addrshm);void *shmaddr = shmat(_shmid, nullptr, 0);if (shmaddr == nullptr){perror("shmat");}std::cout << "who: " << RoleToString(_who) << " attach shm..." << std::endl;return shmaddr;}void DetachShm(void *shmaddr){if (shmaddr == nullptr)return;shmdt(shmaddr);std::cout << "who: " << RoleToString(_who) << " detach shm..." << std::endl;}public:Shm(const std::string &pathname, int proj_id, int who): _pathname(pathname), _proj_id(proj_id), _who(who), _addrshm(nullptr){_key = GetCommKey();if (_who == gCreater)GetShmUseCreate();else if (_who == gUser)GetShmForUse();_addrshm = AttachShm();std::cout << "shmid: " << _shmid << std::endl;std::cout << "_key: " << ToHex(_key) << std::endl;}~Shm(){if (_who == gCreater){int res = shmctl(_shmid, IPC_RMID, nullptr);}std::cout << "shm remove done..." << std::endl;}std::string ToHex(key_t key){char buffer[128];snprintf(buffer, sizeof(buffer), "0x%x", key);return buffer;}bool GetShmUseCreate(){if (_who == gCreater){_shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | IPC_EXCL | 0666);if (_shmid >= 0)return true;std::cout << "shm create done..." << std::endl;}return false;}bool GetShmForUse(){if (_who == gUser){_shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | 0666);if (_shmid >= 0)return true;std::cout << "shm get done..." << std::endl;}return false;}void Zero(){if(_addrshm){memset(_addrshm, 0, gShmSize);}}void *Addr(){return _addrshm;}void DebugShm(){struct shmid_ds ds;int n = shmctl(_shmid, IPC_STAT, &ds);if(n < 0) return;std::cout << "ds.shm_perm.__key : " << ToHex(ds.shm_perm.__key)  << std::endl;std::cout << "ds.shm_nattch: " << ds.shm_nattch << std::endl;}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;void *_addrshm;
};#endif

共享内存虽然速度上占有一定优势,但是共享内存对内存不会提供任何的保护机制,会导致数据不一致的问题,即双方不存在谁等谁的情况,比如我想传一个hello,可能我刚写入一个h就已经被读走了,这样就会导致数据不一致的问题,我们在访问共享内存时,没有任何系统调用,所以速度是所有IPC中最快的。

system V消息队列

  •  消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
  • 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列的接口的使用跟共享内存函数很像。

如果要发消息队列的数据,用:

如果要接收数据,用:

  要查消息队列就用 ipcs -q   ,它的指令跟共享内存就一字之差

 system V信号量

信号量主要用于同步和互斥的。 

System V 信号量是由内核维护的一组整数,它可以被多个进程同时访问和修改。每个信号量代表一个资源的可用数量,进程可以通过对信号量进行操作来控制对资源的访问。信号量的操作包括增加、减少和等待信号量的值达到某个特定条件等。

信号量特点:

  1. 原子性操作:信号量的操作是原子性的,这意味着多个进程同时对信号量进行操作时,系统会保证操作的完整性和一致性,不会出现部分操作完成而其他操作未完成的情况。
  2. 可用于同步和互斥:信号量可以用于实现进程间的同步和互斥。例如,可以使用信号量来确保多个进程不会同时访问同一个共享资源,或者确保一个进程在某个条件满足之前等待另一个进程完成某个任务。
  3. 内核维护:信号量是由内核维护的,这意味着即使进程崩溃或退出,信号量的值也不会丢失。当进程重新启动时,可以继续使用信号量来控制对共享资源的访问。

 进程互斥

  • 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥
  • 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
  • 在进程中涉及到互斥资源的程序段叫临界区 

 多个执行流(进程),都能看到的一份资源:共享资源

被保护起来的资源:临界资源。 用互斥的方式进行保护。

互斥:任何时刻只能有一个进程在访问共享资源。

 信号量的主要作用是用来保护共享资源的。经过保护,共享资源就变成临界资源。

假设上面的方格是电影院的座位。看电影时,只要有了票,位置就一定是你的,而不是谁先坐到就是谁的。 所以成功申请了信号量,即使不访问共享资源,也会留着一部分资源给你。

这里的信号量也叫多元信号量。

对共享资源的整体使用,即资源只有一个,也就是有人用了,别人就用不了了,即互斥。申请信号量时,这种信号量叫二元信号量。 

信号量也是一个公共资源。

信号量本质是一个计数器,申请信号量时,计数器--,也叫P操作。释放信号量时,计数器++,也叫V操作。

信号量的操作

Linux中允许用户一次申请多个信号量,用信号量集保存,信号量集用数组来维护。

如果申请了多个信号量,上面的nsems就是申请的信号量的个数。

如果信号量不需要了,就用 semctl 。 semid就是要删除的信号量集,semnum就是要删除的信号量集的下标。 

 要对信号量进行PV操作,就用 semop  

查看信号量,用 ipcs -s 。删除操作跟前面类似。

最后:

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

相关文章:

【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年11月2日 命名管道&#xff1a; 如果我们想在不相关的进程之间交换数据&#xff0c;可以使用FIFO文件来做这项工作&#xff0c;它经常被称为命名管道。命名管道是一种特殊类型的文…...

[Android]从FLAG_SECURE禁止截屏看surface

在应用中&#xff0c;设置activity的flag为FLAG_SECURE就可以禁止截屏&#xff0c;截屏出来是黑色的&#xff0c; 试验一下&#xff0c; 注意事项 影响&#xff1a; 设置 FLAG_SECURE 标志后&#xff0c;用户将无法对该Activity进行截屏或录制屏幕。这个标志会影响所有屏幕录…...

python 五子棋小游戏

1. 实现效果 Python五子棋小游戏 2. 游戏规则 规则说明&#xff0c;五子棋人机对战游戏规则如下&#xff1a;‌ Ⅰ 默认规则 - 五子棋规则 对局双方‌&#xff1a;各执一色棋子&#xff0c;一方持黑色棋子&#xff0c;另一方持白色棋子。棋盘与开局‌&#xff1a;空棋盘开局…...

JeecgBoot集成工作流实战教程

Activiti是一个轻量级的工作流程和业务流程管理&#xff08;BPM&#xff09;平台&#xff0c;它主要面向业务人员、开发人员和系统管理员。这个平台的核心是一个快速且可靠的Java BPMN 2流程引擎。Activiti是开源的&#xff0c;并且基于Apache许可证进行分发。它可以运行在任何…...

第三十章 章节练习商品列表组件封装

目录 一、需求说明 二、技术要点 三、完整代码 3.1. main.js 3.2. App.vue 3.3. MyTable.vue 3.4. MyTag.vue 一、需求说明 1. my-tag 标签组件封装 (1) 双击显示输入框&#xff0c;输入框获取焦点 (2) 失去焦点&#xff0c;隐藏输入框 (3) 回显标签信息 (4) 内…...

NumPy 高级索引

NumPy 高级索引 NumPy 是 Python 中用于科学计算的核心库之一,它提供了一个强大的N维数组对象和许多用于操作这些数组的函数。在 NumPy 中,除了基本的索引和切片操作外,还提供了高级索引功能,这使得您可以以更加灵活和高效的方式访问和操作数组中的数据。本文将详细介绍 N…...

C/C++常用编译工具链:GCC,Clang

目录 GNU Compiler Collection GCC的优势 编译产生的中间文件 Clang Clang的特点 什么是LLVM&#xff1f; Clang编译过程中产生的中间表示文件 关于Clang的调试 C 编译工具链中有几个主要的编译工具&#xff0c;包括&#xff1a; GNU Compiler Collection (GCC…...

let和war的区别

let和war的区别 看不懂图片&#xff0c;可以看视频教程...

[CUDA] stream使用笔记

文章目录 1. stream一般用法2. stream与event&#xff1a;3. stream异常的排查4. stream的异步与同步行为 1. stream一般用法 cudaStream_t stream_; cudaStreamCreate(&stream_); // create stream // some operators running on this stream_ cudaStreamSynchronize(str…...

第二课:开发工具

在本课中&#xff0c;我们将介绍一些常用的C开发工具&#xff0c;并附上下载链接&#xff0c;帮助你选择合适的工具进行开发。 1. DEVC DEVC 是一个轻量级的C开发工具&#xff0c;适合初学者使用。它提供了基本的代码编辑、编译和调试功能。 下载链接: DEVC 下载 2. Visual…...

Vue 学习随笔系列十三 -- ElementUI 表格合并单元格

ElementUI 表格合并单元格 文章目录 ElementUI 表格合并单元格[TOC](文章目录)一、表头合并二、单元格合并1、示例代码2、示例效果 一、表头合并 参考&#xff1a; https://www.jianshu.com/p/2befeb356a31 二、单元格合并 1、示例代码 <template><div><el-…...

对于一个含有直流和交流分量的信号,如何使用示波器正确显示并测出直流电压值和交流电压峰峰值?

对于一个含有直流&#xff08;DC&#xff09;和交流&#xff08;AC&#xff09;分量的混合信号&#xff0c;使用示波器来正确显示和测量其直流电压值和交流电压峰峰值需要选择适当的设置和方法。以下是详细的步骤&#xff1a; 所需设备 示波器电压探头 步骤一&#xff1a;连…...

移动混合开发面试题及参考答案

目录 什么是混合开发(Hybrid App)? 混合开发(Hybrid App)与原生开发相比有什么优缺点? 优点 缺点 混合开发(Hybrid App)的兴起原因是什么? 市场竞争和成本控制需求 技术发展和资源整合 人才资源的考量 Web App、Native App 和混合开发(Hybrid App)的区别是…...

命令行工具开发秘籍:从零开始创建实用Python脚本(如何创建Python命令行工具)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 创建命令行工具的基础🔖 在非模块化的环境中🔖 在模块化环境中📝 打包和安装模块📝 使用命令行工具⚓️ 相关链接 ⚓️📖 介绍 📖 如何将自己的Python模块打包成一个可在命令行中直接执行的工具?…...

Python - PDF 分割成单页、PDF 转图片(PNG)

文章目录 PDF 分割成一页页的 PDFPDF 转 PNGPDF 分割成一页页的 PDF import fitz def split_pdf(pdf_path, save_dir):source_pdf = fitz.open(pdf_path)# 遍历source_pdf中的每一页,page_number从0开始计数 for idx...

【网络】套接字编程——TCP通信

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;TCP网络服务器简单模拟实现。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff1a;…...

PyTorch实践-CNN-验证码识别

1 需求 GitHub - xhh890921/cnn-captcha-pytorch: 小黑黑讲AI&#xff0c;AI实战项目《验证码识别》 2 接口 含义 在optim.Adam接口中&#xff0c;lr参数代表学习率&#xff08;Learning Rate&#xff09;。学习率是优化算法中的一个关键超参数&#xff0c;它决定了在每次迭代…...

json和pb的比较

1.介绍 在数据序列化和通信领域&#xff0c;schema 指的是用于定义数据结构的模式或结构描述。它描述了数据的字段、类型、嵌套结构和约束&#xff0c;并在数据验证和解释上发挥重要作用。常见的 schema 格式包括 Protocol Buffers (proto)、JSON Schema、XML Schema 等。 Pr…...

Redis-基本了解

一、Redis 初识 Redis 是⼀种基于键值对&#xff08;key-value&#xff09;的NoSQL数据库&#xff0c;与很多键值对数据库不同的是&#xff0c;Redis 中的值可以是由string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、list&#xff08;列表&#xff09…...

HarmonyOS第一课 06 构建更加丰富的页面-习题解析

判断题 1. Tabs组件可以通过接口传入一个TabsController&#xff0c;该TabsController可以控制Tabs组件进行页签切换。T 正确(True) 错误(False) 使用 this.tabsController.changeIndex(this.currentIndex); 可以切换页签 WebviewController提供了变更Web组件显示内容的接口…...

计算机的错误计算(一百四十三)

摘要 探讨 MATLAB 中 附近数的余弦函数的计算精度问题。 例1. 已知 计算 与 直接贴图吧&#xff1a; 另外&#xff0c;16位的正确值分别为 -0.3012758451921695e-7 与 -0.3765996542384011e-10&#xff08;ISRealsoft 提供&#xff09;。 容易看出&#xff0c;MATLAB的输…...

大数据之——Window电脑本地配置hadoop系统(100%包避坑!!方便日常测试,不用再去虚拟机那么麻烦)

之前我们的hadoop不管是伪分布式还是分布式&#xff0c;都是配置在虚拟机上&#xff0c;我们有的时候想要运行一些mapreduce、hdfs的操作&#xff0c;又要把文件移到虚拟机&#xff0c;又要上传hdfs&#xff0c;麻烦得要死&#xff0c;那么有的时候我们写的一些java、python的h…...

汽车固态电池深度报告

固态电池符合未来大容量二次电池发展方向&#xff0c;半固态电池已装车&#xff0c;高端长续航车型、e-VTOL 等方向对固态电池需求明确。固态电池理论上具备更高的能量密度、更好的热稳定性、更长的循环寿命等优点&#xff0c;是未来大容量二次电池发展方向。根据中国汽车动力…...

HTB-Cicada 靶机笔记

Cicada 靶机笔记 概述 HTB 的靶机 Cicada 靶机 靶机地址&#xff1a;https://app.hackthebox.com/machines/Cicada 很有意思且简单的 windows 靶机&#xff0c;这台靶机多次利用了信息枚举&#xff0c;利用不同的信息一步一步获得 root 权限 一、nmap 扫描 1&#xff09;…...

使用DJL和PaddlePaddle的口罩检测详细指南

使用DJL和PaddlePaddle的口罩检测详细指南 完整代码 该项目利用DJL和PaddlePaddle的预训练模型&#xff0c;构建了一个口罩检测应用程序。该应用能够在图片中检测人脸&#xff0c;并将每张人脸分类为“戴口罩”或“未戴口罩”。我们将深入分析代码的每个部分&#xff0c;以便…...

基于stm32的多旋翼无人机(Multi-rotor UAV based on stm32)

在现代无人机技术中&#xff0c;多旋翼无人机因其稳定性和操控性而受到广泛应用。STM32微控制器因其强大的处理能力和丰富的外设接口&#xff0c;成为实现多旋翼无人机控制的理想选择。本文将详细介绍如何基于STM32实现多旋翼无人机的控制&#xff0c;包括硬件设计、软件设计和…...

第二十四章 v-model原理及v-model简化表单类组件封装

目录 一、v-model 原理 二、表单类组件封装 三、v-model简化组件封装代码 一、v-model 原理 原理&#xff1a;v-model本质上是一个语法糖。例如应用在输入框上&#xff0c;就是 value属性 和 input事件 的合写。 作用&#xff1a;提供数据的双向绑定 ① 数据变&#x…...

Java基于SpringBoot 的校园外卖点餐平台微信小程序(附源码,文档)

大家好&#xff0c;我是Java徐师兄&#xff0c;今天为大家带来的是Java基于SpringBoot 的校园外卖点餐平台微信小程序。该系统采用 Java 语言 开发&#xff0c;MySql 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强 &#xff0c;可供大学生实战项目参考使用。 博主介…...

细说STM32单片机USART中断收发RTC实时时间并改善其鲁棒性的方法

目录 一、工程目的 1、 目标 2、通讯协议及应对错误指令的处理目标 二、工程设置 三、程序改进 四、下载与调试 1、合规的指令 2、 proBuffer[0]不是# 3、proBuffer[4]不是; 4、指令长度小于5 5、指令长度大于5 6、proBuffer[2]或proBuffer[3]不是数字 7、;位于p…...

无人机场景 - 目标检测数据集 - 夜间车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍&#xff1a;无人机场景夜间车辆检测数据集&#xff0c;真实场景高质量图片数据&#xff0c;涉及场景丰富&#xff0c;比如夜间无人机场景城市道路行驶车辆图片、夜间无人机场景城市道边停车车辆图片、夜间无人机场景停车场车辆图片、夜间无人机场景小区车辆图片、夜…...