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

Linux——多路复用之poll

目录

前言

一、poll的认识

二、poll的接口

三、poll的使用


前言

前面我们学习了多路复用的select,知道多路复用的原理与select的使用方法,但是select也有许多缺点,导致他的效率不算高。今天我们来学习poll的使用,看看poll较于select的优势。

一、poll的认识

poll与select一样,只负责IO的等的过程,只不过一次可以等待多个文件描述符,他的作用是让read和write不再阻塞。 

  1. 是用来监视多个文件描述符的状态变化的
  2. 程序会停在poll这里等待,直到被监视的文件描述符有一个或多个发生了状态改变

二、poll的接口

poll的接口如下,比select要轻量化很多,只有三个参数

参数1:struct pollfd *fds,pollfd数组首元素地址,

             pollfd是操作系统给我们提供的结构体,主要成员如下

             fd:文件描述符

             events:用户告诉内核,需要关心的fd,上面的事件

             revents:poll返回,内核告诉用户,关心的fd,那些事件就绪

参数2:nfds_t nfds,数组元素个数

参数3:int timeout,毫秒级的等待时间

             timeout > 0 等待timeout毫秒或者有fd就绪再返回。

             timeout == 0 非阻塞轮询。

             timeout == -1 阻塞等待,直到有fd就绪。

返回值:

  1. ret  >  0 :poll等待的多个fd中,已经就需要的fd个数
  2. ret == 0 :poll超时返回
  3. ret  <  0 :poll出错

poll的事件如下,这些值是bit位,可以通过  |(或运算)  的方式写入到events中,我们着重学习POLLIN和POLLOUT,

我们来思考一下这样设计的好处

  1. poll的调用将输入和输出分离,这样就不用一直设置参数。 
  2. 只要系统资源足够,就能一直创建pollfd,解决了等待fd的上限问题。
  3. 不用再自己组织结构,将fd放入其中,现在维护好这个pollfd的结构体数组即可。
  4. 参数变少了,通过或运算就可以添加自己关心的事件
  5. 时间参数timeout使用也很简单。

三、poll的使用

Log.hpp

#pragma once#include <iostream>
#include <cstdarg>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
using namespace std;enum
{Debug = 0,Info,Warning,Error,Fatal
};enum
{Screen = 10,OneFile,ClassFile
};string LevelToString(int level)
{switch (level){case Debug:return "Debug";case Info:return "Info";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "Unknown";}
}const int default_style = Screen;
const string default_filename = "Log.";
const string logdir = "log";class Log
{
public:Log(int style = default_style, string filename = default_filename): _style(style), _filename(filename){if (_style != Screen)mkdir(logdir.c_str(), 0775);}// 更改打印方式void Enable(int style){_style = style;if (_style != Screen)mkdir(logdir.c_str(), 0775);}// 时间戳转化为年月日时分秒string GetTime(){time_t currtime = time(nullptr);struct tm *curr = localtime(&currtime);char time_buffer[128];snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",curr->tm_year + 1900, curr->tm_mon + 1, curr->tm_mday, curr->tm_hour, curr->tm_min, curr->tm_sec);return time_buffer;}// 写入到文件中void WriteLogToOneFile(const string &logname, const string &message){FILE *fp = fopen(logname.c_str(), "a");if (fp == nullptr){perror("fopen failed");exit(-1);}fprintf(fp, "%s\n", message.c_str());fclose(fp);}// 打印日志void WriteLogToClassFile(const string &levelstr, const string &message){string logname = logdir;logname += "/";logname += _filename;logname += levelstr;WriteLogToOneFile(logname, message);}pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void WriteLog(const string &levelstr, const string &message){pthread_mutex_lock(&lock);switch (_style){case Screen:cout << message << endl; // 打印到屏幕中break;case OneFile:WriteLogToClassFile("all", message); // 给定all,直接写到all里break;case ClassFile:WriteLogToClassFile(levelstr, message); // 写入levelstr里break;default:break;}pthread_mutex_unlock(&lock);}// 提供接口给运算符重载使用void _LogMessage(int level, const char *file, int line, char *rightbuffer){char leftbuffer[1024];string levelstr = LevelToString(level);string currtime = GetTime();string  idstr = to_string(getpid());snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s][%s][%s:%d]", levelstr.c_str(), currtime.c_str(), idstr.c_str(), file, line);string messages = leftbuffer;messages += rightbuffer;WriteLog(levelstr, messages);}// 运算符重载void operator()(int level, const char *file, int line, const char *format, ...){char rightbuffer[1024];va_list args;                                              // va_list 是指针va_start(args, format);                                    // 初始化va_list对象,format是最后一个确定的参数vsnprintf(rightbuffer, sizeof(rightbuffer), format, args); // 写入到rightbuffer中va_end(args);_LogMessage(level, file, line, rightbuffer);}~Log(){}private:int _style;string _filename;
};Log lg;class Conf
{
public:Conf(){lg.Enable(Screen);}~Conf(){}
};Conf conf;// 辅助宏
#define lg(level, format, ...) lg(level, __FILE__, __LINE__, format, ##__VA_ARGS__)

Socket.hpp 

#pragma once#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <unistd.h>
using namespace std;
namespace Net_Work
{static const int default_backlog = 5;static const int default_sockfd = -1;using namespace std;enum{SocketError = 1,BindError,ListenError,ConnectError,};// 封装套接字接口基类class Socket{public:// 封装了socket相关方法virtual ~Socket() {}virtual void CreateSocket() = 0;virtual void BindSocket(uint16_t port) = 0;virtual void ListenSocket(int backlog) = 0;virtual bool ConnectSocket(string &serverip, uint16_t serverport) = 0;virtual int AcceptSocket(string *peerip, uint16_t *peerport) = 0;virtual int GetSockFd() = 0;virtual void SetSockFd(int sockfd) = 0;virtual void CloseSocket() = 0;virtual bool Recv(string *buff, int size) = 0;virtual void Send(string &send_string) = 0;// 方法的集中在一起使用public:void BuildListenSocket(uint16_t port, int backlog = default_backlog){CreateSocket();BindSocket(port);ListenSocket(backlog);}bool BuildConnectSocket(string &serverip, uint16_t serverport){CreateSocket();return ConnectSocket(serverip, serverport);}void BuildNormalSocket(int sockfd){SetSockFd(sockfd);}};class TcpSocket : public Socket{public:TcpSocket(int sockfd = default_sockfd): _sockfd(sockfd){}~TcpSocket() {}void CreateSocket() override{_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_sockfd < 0)exit(SocketError);}void BindSocket(uint16_t port) override{int opt = 1;setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n < 0)exit(BindError);}void ListenSocket(int backlog) override{int n = listen(_sockfd, backlog);if (n < 0)exit(ListenError);}bool ConnectSocket(string &serverip, uint16_t serverport) override{struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(serverport);// addr.sin_addr.s_addr = inet_addr(serverip.c_str());inet_pton(AF_INET, serverip.c_str(), &addr.sin_addr);int n = connect(_sockfd, (sockaddr *)&addr, sizeof(addr));if (n == 0)return true;return false;}int AcceptSocket(string *peerip, uint16_t *peerport) override{struct sockaddr_in addr;socklen_t len = sizeof(addr);int newsockfd = accept(_sockfd, (sockaddr *)&addr, &len);if (newsockfd < 0)return -1;// *peerip = inet_ntoa(addr.sin_addr);// INET_ADDRSTRLEN 是一个定义在头文件中的宏,表示 IPv4 地址的最大长度char ip_str[INET_ADDRSTRLEN];inet_ntop(AF_INET, &addr.sin_addr, ip_str, INET_ADDRSTRLEN);*peerip = ip_str;*peerport = ntohs(addr.sin_port);return newsockfd;}int GetSockFd() override{return _sockfd;}void SetSockFd(int sockfd) override{_sockfd = sockfd;}void CloseSocket() override{if (_sockfd > default_sockfd)close(_sockfd);}bool Recv(string *buff, int size) override{char inbuffer[size];ssize_t n = recv(_sockfd, inbuffer, size - 1, 0);if (n > 0){inbuffer[n] = 0;*buff += inbuffer;return true;}elsereturn false;}void Send(string &send_string) override{send(_sockfd, send_string.c_str(),send_string.size(),0);}private:int _sockfd;string _ip;uint16_t _port;};
}

 PollServer.hpp

#pragma once
#include <iostream>
#include <string>
#include <poll.h>
#include <memory>
#include "Log.hpp"
#include "Socket.hpp"using namespace Net_Work;
const static int gdefaultport = 8888;
const static int gbacklog = 8;
const static int gnum = 1024;
class PollServer
{
public:PollServer(int port) : _port(port), _num(gnum), _listensock(new TcpSocket()){}void HandlerEvent(){for (int i = 0; i < _num; i++){if (_rfds[i].fd == -1)continue;int fd = _rfds[i].fd;short revents = _rfds[i].revents;// 判断事件是否就绪if (revents & POLLIN){// 读事件分两类,一类是新链接到来,一类是新数据到来if (fd == _listensock->GetSockFd()){// 新链接到来lg(Info, "get a new link");// 获取连接std::string clientip;uint16_t clientport;int sockfd = _listensock->AcceptSocket(&clientip, &clientport);if (sockfd == -1){lg(Error, "accept error");continue;}lg(Info, "get a client,client info is# %s:%d,fd: %d", clientip.c_str(), clientport, sockfd);// 此时获取连接成功了,但是不能直接read write,sockfd仍需要交给poll托管 -- 添加到数组_rfds中int pos = 0;for (; pos < _num; pos++){if (_rfds[pos].fd == -1){_rfds[pos].fd = sockfd;_rfds[pos].events = POLLIN;lg(Info, "get a new link, fd is : %d", sockfd);break;}}if (pos == _num){// 1.扩容// 2.关闭close(sockfd);lg(Warning, "server is full, be carefull...");}}else{// 普通的读事件就绪char buffer[1024];ssize_t n = recv(fd, buffer, sizeof(buffer-1), 0);if (n > 0){buffer[n] = 0;lg(Info, "client say# %s", buffer);std::string message = "你好,同志";message += buffer;send(fd, message.c_str(), message.size(), 0);}else{lg(Warning, "client quit ,maybe close or error,close fd: %d", fd);close(fd);// 还要取消poll的关心_rfds[i].fd = -1;_rfds[i].events = 0;_rfds[i].revents = 0;}}}}}void InitServer(){_listensock->BuildListenSocket(_port, gbacklog);_rfds = new struct pollfd[_num];for (int i = 0; i < _num; i++){_rfds[i].fd = -1;_rfds[i].events = 0;_rfds[i].revents = 0;}// 最开始的时候,只有一个文件描述符,Listensock_rfds[0].fd = _listensock->GetSockFd();_rfds[0].events |= POLLIN;}void Loop(){_isrunning = true;// 循环重置select需要的rfdswhile (_isrunning){// 定义时间int timeout = 1000;//PrintDebug();// rfds是输入输出型参数,rfds是在select调用返回时,不断被修改,所以每次需要重置rfdsint n = poll(_rfds, _num, timeout);switch (n){case 0:lg(Info, "select timeout...");break;case -1:lg(Error, "select error!!!");default:// 正常就绪的fdlg(Info, "select success,begin event handler");HandlerEvent();break;}}_isrunning = false;}void Stop(){_isrunning = false;}void PrintDebug(){// std::cout << "current select rfds list is :";// for (int i = 0; i < num; i++)// {//     if (_rfds_array[i] == nullptr)//         continue;//     else//         std::cout << _rfds_array[i]->GetSockFd() << " ";// }// std::cout << std::endl;}private:std::unique_ptr<Socket> _listensock;int _port;bool _isrunning;struct pollfd *_rfds;int _num;
};

 Main.cc

#include <iostream>
#include <memory>
#include "PollServer.hpp"void Usage(char* argv)
{std::cout<<"Usage: \n\t"<<argv<<" port\n"<<std::endl;
}
// ./select_server 8080
int main(int argc,char* argv[])
{// std::cout<<num<<std::endl;       1024if(argc!=2){Usage(argv[0]);return -1;}uint16_t localport = std::stoi(argv[1]);std::unique_ptr<PollServer> svr = std::make_unique<PollServer>(localport);svr->InitServer();svr->Loop();return 0;
}

运行结果如下,由于我们poll第三个参数设置的是1000ms,因此每一秒poll都会返回,当发现有新链接的时候,就回去执行函数,在函数中调用write或者read变不会再阻塞了。 

四、poll的优缺点

优点

  1. 可以等待多个fd,效率高
  2. 输入输出函数分离,events和revents,不用再频繁对poll参数进行重置了
  3. poll关心的fd没有上线

缺点

  1. 用户到内核空间,要有数据拷贝                ——必要开销
  2. poll应用层,仍需要遍历(遍历查看哪个fd中哪个事件就绪,新链接需要交给poll,也需要遍历找到没有fd占用的地方)
  3. 在内核层面,OS也要遍历检测关心的fd是否有对应的事件就绪(在poll调用时候发生)

相关文章:

Linux——多路复用之poll

目录 前言 一、poll的认识 二、poll的接口 三、poll的使用 前言 前面我们学习了多路复用的select&#xff0c;知道多路复用的原理与select的使用方法&#xff0c;但是select也有许多缺点&#xff0c;导致他的效率不算高。今天我们来学习poll的使用&#xff0c;看看poll较于…...

【AI资讯】7.19日凌晨OpenAI发布迷你AI模型GPT-4o mini

性价比最高的小模型 北京时间7月19日凌晨&#xff0c;美国OpenAI公司推出一款新的 AI 模型“GPT-4o mini”&#xff0c;即GPT-4o的更小参数量、简化版本。OpenAI表示&#xff0c;GPT-4o mini是目前功能最强大、性价比最高的小参数模型&#xff0c;性能逼近原版GPT-4&#xff0…...

3.设计模式--创建者模式--工厂模式

3.设计模式–创建者模式–工厂模式 3.1简单工厂和静态 工厂&#xff08;不属于23中设计模式&#xff09; //抽象类&#xff1a;定义了产品的规范&#xff0c;描述了产品的主要特性和功能 public interface Tea {public abstract void setName();public abstract String getNa…...

IOT 的 10 种常见协议、组网模式、特点及其使用场景浅析

前情&#xff1a; 开放系统互连&#xff08;OSI&#xff09;模型&#xff0c;它列出了七层。从下到上&#xff0c;各层如下&#xff1a; 物理层 数据链接 网络层 传输层 会话层 推介会 应用层 物联网也以多层模型的形式表达。尽管有些使用 OSI 七层模型&#xff0c;但其…...

【Android】 dp与sp,加冕为王

目录 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 基础知识&#xff1a; ppi pt DPI 的定义和重要性 Android 中的 DPI 级别 px dp&#xff08;Density Independent Pixels&#xff09; sp&#xff08;Scale-independent Pixels&#xff09; 安卓的dp/dip、sp 虚拟…...

R语言画散点图-饼图-折线图-柱状图-箱线图-直方图-曲线图-热力图-雷达图

R语言画散点图-饼图-折线图-柱状图-箱线图-直方图-曲线图-热力图-雷达图 散点图示例解析效果 饼图示例解析效果 折线图示例解析效果 柱状图示例解析效果 箱线图示例解析效果 直方图示例解析效果 曲线图使用 curve() 函数示例效果 使用 plot() 函数示例效果 使用 ggplot2 包绘制…...

影响转化率的多元因素分析及定制开发AI智能名片S2B2C商城系统小程序的应用案例

摘要&#xff1a;在互联网时代&#xff0c;转化率是衡量营销活动成功与否的关键指标。本文首先分析了影响转化率的多种因素&#xff0c;包括活动页面的设计、活动的限时性、主题文案的吸引力、从众心理的运用&#xff0c;以及最核心的产品质量与优惠力度。接着&#xff0c;本文…...

数据仓库中事实表设计的关键步骤解析

在数据仓库的设计过程中&#xff0c;事实表是描述业务度量的核心组件。本文将深入探讨数据仓库中事实表设计的关键步骤&#xff0c;包括选择业务过程及确定事实表类型、声明粒度、确定维度和确定事实的过程&#xff0c;帮助读者更好地理解和应用事实表设计的原则和方法。 第一…...

.net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段

Program.cs 安装包&#xff1a;Microsoft.AspNetCore.Hosting.WindowsServices、Microsoft.Extensions.Hosting、Microsoft.Extensions.Hosting.WindowsServices、Microsoft.Extensions.Logging.Log4Net.AspNetCore 新建Configs/log4net.config using Com.Chinahorn.Exchange.W…...

通过 EMR Serverless Spark 提交 PySpark 流任务

在大数据快速发展的时代&#xff0c;流式处理技术对于实时数据分析至关重要。EMR Serverless Spark提供了一个强大而可扩展的平台&#xff0c;它不仅简化了实时数据处理流程&#xff0c;还免去了服务器管理的烦恼&#xff0c;提升了效率。本文将指导您使用EMR Serverless Spark…...

【Linux网络】epoll实现的echo服务器{nocopy类/智能指针/echo服务器}

文章目录 1.代码基础1.1某类唯一存在1.2C智能指针 2.epoll实现的echo服务器日志套接字CMakeepoll封装主函数服务器 1.代码基础 1.1某类唯一存在 这段代码定义了一个名为 nocopy 的类&#xff0c;它旨在防止该类的实例被复制或赋值。这是通过在类中显式删除拷贝构造函数&#…...

[数据集][目标检测]拐杖检测数据集VOC+YOLO格式2778张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2778 标注数量(xml文件个数)&#xff1a;2778 标注数量(txt文件个数)&#xff1a;2778 标注…...

长按加速- 解决react - setInterval下无法更新问题

最开始直接setInterval里&#xff0c;useState硬写&#xff0c;发现更新不&#xff0c;固定值 换let&#xff0c;发现dom更新不了 正确做法是用ref 并且pc端可以长按的&#xff0c;只是要用onTouchStart&#xff0c;不要用onMouseDown onTouchStart{handleMouseDown} onTou…...

路网双线合并单线——ArcGIS 解决方法

路网双线合并成单线是一个在地图制作、交通规划以及GIS分析中常见的需求。双线路网定义&#xff1a;具有不同流向、不同平面结构的道路。此外&#xff0c;车道数较多的道路&#xff08;例如&#xff0c;双黄实线车道数大于4的道路&#xff09;也可以视为双线路网&#xff0c;本…...

【.NET全栈】ASP.NET开发Web应用——ADO.NET数据访问技术

文章目录 前言一、ADO.NET基础1、ADO.NET架构2、ADO.NET数据提供者 二、连接数据库1、SqlConnection数据库连接类2、使用SqlConnectionStringBuilder连接字符串3、关闭和释放连接4、在web.config配置文件中保存连接字符串5、连接池技术 三、与数据库交互1、使用SqlCommand操作数…...

【机器学习】无监督学习和自监督学习

1. 什么是机器学习 机器学习是一种使计算机系统能够从数据中学习并做出预测或决策的技术和科学领域。它不需要显式地编程来执行特定任务&#xff0c;而是通过使用算法来分析数据和识别模式&#xff0c;以此“学习”如何做出准确的预测或决策。 以下是机器学习的几个关键点&…...

蓝牙新篇章:WebKit的Web Bluetooth API深度解析

蓝牙新篇章&#xff1a;WebKit的Web Bluetooth API深度解析 在物联网(IoT)时代&#xff0c;Web应用与物理设备的交互变得越来越重要。WebKit的Web Bluetooth API开启了一个新时代&#xff0c;允许Web页面直接与蓝牙设备通信。这一API不仅提高了用户体验&#xff0c;还为创新的…...

2024可信数据库发展大会:TDengine CEO 陶建辉谈“做难而正确的事情”

在当前数字经济快速发展的背景下&#xff0c;可信数据库技术日益成为各行业信息化建设的关键支撑点。金融、电信、能源和政务等领域对数据处理和管理的需求不断增加&#xff0c;推动了数据库技术的创新与进步。与此同时&#xff0c;人工智能与数据库的深度融合、搜索与分析型数…...

Guns v7.3.0:基于 Vue3、Antdv 和 TypeScript 打造的开箱即用型前端框架

摘要 本文深入探讨了Guns v7.3.0前端项目&#xff0c;该项目是基于Vue3、Antdv和TypeScript的前端框架&#xff0c;以Vben Admin的脚手架为基础进行了改造。文章分析了Guns 7.3.0的技术特点&#xff0c;包括其使用Vue3、vite2和TypeScript等最新前端技术栈&#xff0c;以及提供…...

掌握构建艺术:在Gradle中配置自定义的源代码管理(SCM)

掌握构建艺术&#xff1a;在Gradle中配置自定义的源代码管理&#xff08;SCM&#xff09; 在软件开发过程中&#xff0c;源代码管理&#xff08;Source Code Management&#xff0c;简称SCM&#xff09;是不可或缺的一部分。它帮助开发者管理代码的变更历史&#xff0c;支持团…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化

iOS 应用的发布流程一直是开发链路中最“苹果味”的环节&#xff1a;强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说&#xff0c;这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发&#xff08;例如 Flutter、React Na…...