Linux网络:网络套接字-TCP回显服务器——多进程/线程池(生产者消费者模型)
1.多进程版本
这里选择创建子进程,让子进程再创建子进程。父进程等待子进程,子进程的子进程处理业务逻辑。因为子进程是直接退出,子进程的子进程变成孤儿进程被系统管理,所以父进程在等待的时候不是阻塞等待的,所以可以处理多条链接请求。或者可以忽略SIGCHID信号让子进程不需要等待。
服务端
pragma once #include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/wait.h>#define DEF_PORT 8081class TcpSever
{private:int port;int listen_sock;//监听套接字public: TcpSever(int _port=DEF_PORT):port(_port),listen_sock(-1){}void InitSever(){listen_sock=socket(AF_INET,SOCK_STREAM,0);//IPV4流式套接if(listen_sock<0){std::cerr<<"监听套接字创建失败"<<std::endl;exit(-1);}//绑定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;//随机绑定服务器ipif(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"绑定失败"<<std::endl;exit(-2);}//建立链接
#define BACK_LOG 5if(listen(listen_sock,BACK_LOG)<0){std::cerr<<"链接失败"<<std::endl;exit(-3);}}//获取链接void Loop(){//获取客户端信息struct sockaddr_in client;//signal(SIGCHID,hander);//hander是信号捕捉方法while(true){socklen_t len=sizeof(client);//获取新链接int sock=accept(listen_sock,(struct sockaddr*)&client,&len);if(sock<0){std::cerr<<"接受链接失败"<<std::endl;continue;//继续接受其他链接请求}//多进程处理多个客户端pid_t id=fork();if(id==0)//子进程{//子进程,与子进程的子进程不关心listen_sockclose(listen_sock);if(fork()>0){exit(0);//子进程直接退出后子进程的子进程变为孤儿进程被守护进程接管,不用等待了}//子进程的子进程,处理业务std::cout<<"获取新连接成功! ip["<<inet_ntoa(client.sin_addr)<<"] port["<<ntohs(client.sin_port)<<"]"<<std::endl;//整数ip转为字符ip形式,网络字节端口转化为本地端口//开始服务std::string CIp=inet_ntoa(client.sin_addr);int CPort=ntohs(client.sin_port);Sever(sock,CIp,CPort);exit(0);}//不能使用阻塞等待,可以使用信号机制忽略SIGCHID信号,或者使用两次fork函数close(sock);//父进程不关心客户端的链接请求,请求交给子进程做。waitpid(id,nullptr,0);//不会阻塞,因为id进程创建完子进程会立即退出,所以不会阻塞。}}void Sever(int sock,std::string&ip,int port){char buff[1024];while(true){memset(buff,0,sizeof(buff));ssize_t ReadSize=read(sock,buff,sizeof(buff)-1);if(ReadSize>0){buff[ReadSize]='\0';//添加字符串结束标志std::cout<<"Client["<<ip<<"-port-"<<port<<"]# "<<buff<<std::endl;write(sock,buff,ReadSize);//向客户端写入数据}else if(ReadSize==0){//对端关闭链接std::cout<<"Client["<<ip<<"-port-"<<port<<"]# 关闭"<<std::endl;break;}else{std::cerr<<sock<<"读取错误"<<std::endl;break;}}std::cout<<"服务终止"<<std::endl;}~TcpSever(){if(listen_sock>=0){close(listen_sock);}}
};
启动服务端
#include"Tcp_Sever.h"// Tcp_Sever +portvoid User(char*name)
{std::cout<<name<<" + port"<<std::endl;
}int main(int argc,char*argv[])
{if(argc!=2){User(argv[0]);exit(-1);}TcpSever*Sever=new TcpSever(atoi(argv[1]));//将字符串形式的端口号转化为整数形式Sever->InitSever();Sever->Loop();return 0;
}
客户端
#pragma once#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string>
#include<string.h>class TcpClient
{private:std::string sev_ip;//服务器ipint sev_port;int sock;public:TcpClient(std::string _ip,int _sev_port):sev_ip(_ip),sev_port(_sev_port),sock(-1){}void InitClient(){sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){std::cerr<<"创建套接字失败"<<std::endl;exit(-1);}//客户端不需要绑定监听}//启动客户端void Start(){//向服务器发送链接//填充服务器信息struct sockaddr_in sever;memset(&sever,0,sizeof(sever));sever.sin_family=AF_INET;sever.sin_port=htons(sev_port);//服务器开放的端口sever.sin_addr.s_addr=inet_addr(sev_ip.c_str());//服务器的ip地址if(connect(sock,(struct sockaddr*)&sever,sizeof(sever))==0){//与服务器交互std::cout<<"发送交互请求成功"<<std::endl;Request(sock);}else{std::cerr<<"交互失败"<<std::endl;}}void Request(int Sock){std::string meg;while(true){std::cout<<"输入信息#";std::cin>>meg;char buff[1024];write(Sock,meg.c_str(),meg.size());//读取服务器发送的消息ssize_t ReadSize=read(sock,buff,sizeof(buff)-1);if(ReadSize>0){buff[ReadSize]='\0';}std::cout<<"Sever#"<<buff<<std::endl;}}~TcpClient(){if(sock>=0){close(sock);}}
};
启动客户端
#include"Tcp_Client.h"// ./Tcp_Client +ip +portvoid User(char*name)
{std::cout<<name<<" + sever_ip + sever_port"<<std::endl;
}int main(int argc,char*argv[])
{if(argc!=3){User(argv[0]);exit(-1);}TcpClient*Client=new TcpClient(argv[1],atoi(argv[2]));Client->InitClient();Client->Start();return 0;
}
2.多线程版本
注意:在类内部的成员函数,调用类内非静态成员函数时会自动带this指针。而线程执行的函数要求void* Hander(void*)
类型,所以线程执行函数要用static修饰。
服务端
#pragma once #include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/wait.h>
#include<pthread.h>#define DEF_PORT 8081//通信结构体
class Pragram{public:int sock;std::string ip;int port;Pragram(int _sock,std::string _ip,int _port):sock(_sock),ip(_ip),port(_port){}
};class TcpSever
{private:int port;int listen_sock;//监听套接字public: TcpSever(int _port=DEF_PORT):port(_port),listen_sock(-1){}void InitSever(){listen_sock=socket(AF_INET,SOCK_STREAM,0);//IPV4流式套接if(listen_sock<0){std::cerr<<"监听套接字创建失败"<<std::endl;exit(-1);}//绑定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;//随机绑定服务器ipif(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"绑定失败"<<std::endl;exit(-2);}//建立链接
#define BACK_LOG 5if(listen(listen_sock,BACK_LOG)<0){std::cerr<<"链接失败"<<std::endl;exit(-3);}std::cout<<"服务启动成功"<<std::endl;}//获取链接void Loop(){//获取客户端信息struct sockaddr_in client;//signal(SIGCHID,hander);//hander是信号捕捉方法while(true){socklen_t len=sizeof(client);//获取新链接int sock=accept(listen_sock,(struct sockaddr*)&client,&len);if(sock<0){std::cerr<<"接受链接失败"<<std::endl;continue;//继续接受其他链接请求}pthread_t tid;std::string ip=inet_ntoa(client.sin_addr);int port=ntohs(client.sin_port);Pragram*msg=new Pragram(sock,ip,port);pthread_create(&tid,nullptr,HanderQuest,msg);}}private:static void* HanderQuest(void*arg){Pragram*msg=(Pragram*)arg;pthread_detach(pthread_self());//线程分离std::cout<<"获取新连接成功"<<"[ ip:"<<msg->ip<<" port:"<<msg->port<<" ]"<<std::endl;Sever(msg->sock,msg->ip,msg->port);close(msg->sock);delete msg;return nullptr;}static void Sever(int sock,std::string&ip,int port){char buff[1024];while(true){memset(buff,0,sizeof(buff));ssize_t ReadSize=read(sock,buff,sizeof(buff)-1);if(ReadSize>0){buff[ReadSize]='\0';//添加字符串结束标志std::cout<<"Client["<<ip<<"-port-"<<port<<"]# "<<buff<<std::endl;write(sock,buff,ReadSize);//向客户端写入数据}else if(ReadSize==0){//对端关闭链接std::cout<<"Client["<<ip<<"-port-"<<port<<"]# 关闭"<<std::endl;break;}else{std::cerr<<sock<<"读取错误"<<std::endl;break;}}std::cout<<"服务终止"<<std::endl;}~TcpSever(){if(listen_sock>=0){close(listen_sock);}}
};
客户端代码部分不变。
3.模板线程池版本
线程池代码:
PthreadPool.h
#pragma once #include<iostream>
#include<pthread.h>
#include<queue>#define NUM 5template<typename Task>
class ThreadPool
{private:std::queue<Task> _task_queue;//临界资源pthread_mutex_t _lock;int _thread_num;pthread_cond_t _cond;public:ThreadPool(int Num=NUM):_thread_num(Num){pthread_mutex_init(&_lock,nullptr);pthread_cond_init(&_cond,nullptr);}bool IsEmpty(){return _task_queue.empty();}static void*Routine(void*arg)//静态函数无隐含的this指针{pthread_detach(pthread_self());ThreadPool<Task>*self=(ThreadPool<Task>*)arg;while(true){pthread_mutex_lock(&(self->_lock));while(self->IsEmpty())//循环检测临界资源是否就绪{//休眠pthread_cond_wait(&(self->_cond),&(self->_lock));}//任务队列有任务Task t;self->Pop(t);pthread_mutex_unlock(&(self->_lock));//解锁后处理任务t.Run();}}void Push(const Task&in)//外部添加任务{pthread_mutex_lock(&_lock);_task_queue.push(in);//唤醒一个线程pthread_cond_signal(&_cond);pthread_mutex_unlock(&_lock);}void Pop(Task&out)//线程获取任务{out=_task_queue.front();_task_queue.pop();}~ThreadPool(){pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_cond);}void InitThreadPool(){pthread_t tid;for(int i=0;i<_thread_num;i++){//为了避免传参时C++传this指针,在线程执行方法上带static。//传参数时将this指针传到线程执行方法上。 pthread_create(&tid,nullptr,Routine,this);}}
};
设计任务Task.h
#pragma once #include<iostream>
#include<string>
#include<unistd.h>
#include<string.h>struct Hander{void operator()(int sock,std::string&ip,int port){char buff[1024];while(true){memset(buff,0,sizeof(buff));ssize_t ReadSize=read(sock,buff,sizeof(buff)-1);if(ReadSize>0){buff[ReadSize]='\0';//添加字符串结束标志std::cout<<"Client["<<ip<<"-port-"<<port<<"]# "<<buff<<std::endl;write(sock,buff,ReadSize);//向客户端写入数据}else if(ReadSize==0){//对端关闭链接std::cout<<"Client["<<ip<<"-port-"<<port<<"]# 关闭"<<std::endl;break;}else{std::cerr<<sock<<"读取错误"<<std::endl;break;}}std::cout<<"服务终止"<<std::endl;close(sock);}
};class Task{private:int sock;std::string ip;int port;Hander condut;//仿函数public:Task()=default;Task(int _sock,std::string _ip,int _port):sock(_sock),ip(_ip),port(_port){}void Run(){condut(sock,ip,port);}};
服务端代码
#pragma once #include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/wait.h>
#include<pthread.h>#include"ThreadPool.h"
#include"Task.h"#define DEF_PORT 8081//通信结构体
class Pragram{public:int sock;std::string ip;int port;Pragram(int _sock,std::string _ip,int _port):sock(_sock),ip(_ip),port(_port){}
};class TcpSever
{private:int port;int listen_sock;//监听套接字ThreadPool<Task>*Pool;public: TcpSever(int _port=DEF_PORT):port(_port),listen_sock(-1),Pool(nullptr){}void InitSever(){listen_sock=socket(AF_INET,SOCK_STREAM,0);//IPV4流式套接if(listen_sock<0){std::cerr<<"监听套接字创建失败"<<std::endl;exit(-1);}//绑定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;//随机绑定服务器ipif(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"绑定失败"<<std::endl;exit(-2);}//建立链接
#define BACK_LOG 5if(listen(listen_sock,BACK_LOG)<0){std::cerr<<"链接失败"<<std::endl;exit(-3);}std::cout<<"服务启动成功"<<std::endl;Pool=new ThreadPool<Task>(10);//10个线程}//获取链接void Loop(){Pool->InitThreadPool();//获取客户端信息struct sockaddr_in client;//signal(SIGCHID,hander);//hander是信号捕捉方法while(true){socklen_t len=sizeof(client);//获取新链接int sock=accept(listen_sock,(struct sockaddr*)&client,&len);if(sock<0){std::cerr<<"接受链接失败"<<std::endl;continue;//继续接受其他链接请求}std::string ip=inet_ntoa(client.sin_addr);int port=ntohs(client.sin_port);Task asig(sock,ip,port);Pool->Push(asig);}}~TcpSever(){if(listen_sock>=0){close(listen_sock);}}
};
客户端代码不需要改变
相关文章:
Linux网络:网络套接字-TCP回显服务器——多进程/线程池(生产者消费者模型)
1.多进程版本 这里选择创建子进程,让子进程再创建子进程。父进程等待子进程,子进程的子进程处理业务逻辑。因为子进程是直接退出,子进程的子进程变成孤儿进程被系统管理,所以父进程在等待的时候不是阻塞等待的,所以可…...

Redis 篇-深入了解基于 Redis 实现消息队列(比较基于 List 实现消息队列、基于 PubSub 发布订阅模型之间的区别)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 消息队列的认识 2.0 基于 List 实现消息队列 2.1 基于 List 实现消息队列的优缺点 3.0 基于 PubSub 实现消息队列 3.1 基于 PubSub 的消息队列优缺点 4.0 基于 St…...

python 学习一张图
python学习一张图,python的特点的是学的快,一段时间不用,忘记的也快,弄一张图及一些入门案例吧。 写一个简单的测试: #!/usr/bin/python # -*- coding: UTF-8 -*- import osdef add_num(a, b):return a bif __name__…...
通过Docker部署 MongoDB 服务器
今天我们将在三丰云的免费服务器上进行 MongoDB 的部署测试。这款不错的免费服务器提供了很好的性能,1核CPU、1G内存、10G硬盘和5M带宽,足以满足我们的基本需求。三丰云的服务稳定,操作简单,真是一个值得推荐的选择,特…...

无人机避障雷达技术详解
随着无人机技术的飞速发展,其应用领域已经从最初的军事领域扩展到商业、农业、建筑巡检、应急救援、物流运输等多个领域。在这些多样化的应用场景中,无人机的安全性和稳定性显得尤为重要。无人机避障技术作为保障无人机安全飞行的核心技术之一࿰…...

2009-2023年上市公司华证esg评级评分数据(年度+季度)(含细分项)
2009-2023年上市公司华证esg评级评分数据(年度季度)(含细分项) 1、时间:2009-2023年 2、来源:整理自wind 3、指标:证券代码、年份、证券简称、评级日期、综合评级、综合得分、E评级、E得分、…...
C++ 模板进阶知识——stdenable_if
目录 C 模板进阶知识——std::enable_if1. 简介和背景基本语法使用场景 2. std::enable_if 的基本用法示例:限制函数模板只接受整数类型 3. SFINAE 和 std::enable_if示例:使用 SFINAE 进行函数重载SFINAE 的优点应用场景 4. 在类模板中使用 std::enable…...

国内外ChatGPT网站集合,无限制使用【2024-09最新】~
经过我一年多以来,使用各种AI工具的体验,我收集了一批AI工具和站点 这些工具都是使用的最强最主流的模型,也都在各个领域里都独领风骚的产品。 而且,这些工具你都可以无限制地使用。 无论你是打工人、科研工作者、学生、文案写…...
如何在VUE3中使用函数式组件
在Vue 3中,函数式组件的概念与Vue 2相似,但实现方式有所不同。函数式组件是一种无状态、无实例的组件,它们只根据传入的props和context来渲染输出。在Vue 3中,你可以通过定义一个函数并返回一个渲染函数来使用函数式组件。但是&am…...
linux访问外网的设置
Ubuntu | LUCKFOX WIKI 开发板配置 添加路由信息 sudo route add default gw 172.32.0.100添加 DNS servers 打开文件 sudo vi /etc/resolv.conf添加以下内容: nameserver 8.8.8.8联网测试 ping www.baidu.com开机自动配置 路由信息和 DNS servers 重启后会被清除,我们创建…...

PHP轻松创建高效收集问卷调查小程序系统源码
轻松创建,高效收集 —— 问卷调查小程序,你的调研神器! 一、告别繁琐,一键开启调研之旅 还在为设计问卷、收集数据而头疼不已吗?现在,有了“问卷调查小程序”,一切都变得轻松简单!无…...

Redis面试必问:Redis为什么快?Redis五大基本数据类型
请记住胡广一句话,所有的中间件所有的框架都是建立在基础之上,数据结构,计算机网络,计算机原理大伙一定得看透!!~ 1. Redis快的秘密 相信大部分Redis初学者都会忽略掉一个重要的知识点,Redis…...
InternVL2- dockerfile环境变量持久化使用`ENV`而不是`RUN export`来设置环境变量,以确保环境变量在容器运行时仍然可用
在Dockerfile中使用RUN export命令设置环境变量并不是一种持久化的方式。当你在Dockerfile中使用export命令时,它只会在当前构建阶段生效,并不会被持久化到生成的镜像中。这是因为export命令实际上是在shell环境中设置环境变量,而Docker构建过…...

Python(PyTorch和TensorFlow)图像分割卷积网络导图(生物医学)
🎯要点 语义分割图像三层分割椭圆图像脑肿瘤图像分割动物图像分割皮肤病变分割多模态医学图像多尺度特征生物医学肖像多类和医学分割通用图像分割模板腹部胰腺图像分割分类注意力网络病灶边界分割气胸图像分割 Python生物医学图像卷积网络 该网络由收缩路径和扩…...

DevOps实现CI/CD实战(七)- Jenkins集成k8s实现自动化CI
自动化CI操作 1. 安装gitlab plugin 工具 ##### 2. 配置流水线任务的构建触发器,复制URL:http://192.168.201.111:8080/project/pipeline 3. Gitlab配置Webhooks,将上面的url:http://192.168.201.111:8080/project/pipeline粘…...
从ES6到ES2023 带你深入了解什么是ES
从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功…...
openVX加速-常见问题:适用场景、AI加速、安装方式等
1. 哪些算法处理推荐使用 OpenVX OpenVX 是非常适合图像处理和计算机视觉任务的框架,特别是在需要高性能和硬件加速的场景下。如果你的前处理和后处理涉及到图像滤波、边缘检测、颜色转换等操作,使用 OpenVX 可以带来性能提升。 OpenVX 更适合处理以下…...

国产芯片LT8711HE:TYPE-C/DP1.2转HDMI2.0转换器,4k60Hz高分辨率
以下为LT8711HE芯片的简单介绍,如有介绍不尽之处,请指出 LT8711HE是一个高性能的Type-C/DP1.2到HDMI2.0转换器,用于连接USB Type-C源或DP1.2源到HDMI2.0接收器。 LT8711HE集成了一个DP1.2兼容的接收器和一个HDMI2.0兼容的发射器。另外&…...

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey
Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs&…...

Java+Swing用户信息管理系统
JavaSwing用户信息管理系统 一、系统介绍二、功能展示1.管理员登陆2.用户信息查询3.用户信息添加4.用户信息修改5.用户信息删除 三、系统实现1.UserDao .java 四、其它1.其他系统实现 一、系统介绍 该系统实现了管理员系统登陆、用户信息查询、用户信息添加、用户信息修改、用…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

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 抗噪声…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...