UDP客户端服务器通信

        在这篇博客中,我们将探索 UDP(用户数据报协议) 通信,简要地说,UDP 是一种无连接、快速但不可靠的通信协议,适用于需要快速数据传输但对丢包容忍的场景,比如视频流和在线游戏。就像《我是如此相信》的图片所表达的那样,UDP 没有过多的保障机制,它直接、简单、快捷,就像信念一样,直接而坚定。 

1、网络协议中的下三层主要解决的是,数据安全可靠得发送到远端机器

2、用户使用应用层软件,完成数据的发送和接收,先把软件启动起来,那就是进程,因此网络通信的本质就是进程间的通信。

一、认识端口号

端口号无论是客户端还是服务器,都能唯一的标识该主机上的一个特定应用层的进程,ip地址唯一的标识一个主机,端口号只能用来标识该主机上的唯一进程。IP+Port能够标识全网唯一的进程。

二、套接字

客户端和服务器通信的时候就好像插头和插座的关系

端口号VS进程pid,但是pid已经可以唯一标识一个进程,为什么还要端口号?

1、不是所有的进程都要网络通信

2、pid属于操作系统中的进程管理,但是要是系统出问题,网络部分也要改,牵一发而动全身,因此要解耦。

我们的客户端怎么知道服务器的端口号?每个服务器的端口必须是众所周知的,被客户端知道。

一个进程可以绑定多个端口号,一个端口号不可以被多个进程绑定。经过哈希找的进程就不一样了

2、  套接字的种类:域间(本地通信)、原始(编写网络工具,抓包)和网络套接字

三、UDP和TCP

TCP(Transmission Control Protocol,传输控制协议)网络必须连通

  • 面向连接:在数据传输之前,发送端和接收端需要通过三次握手建立连接。这一过程确保了双方都准备好进行数据传输,并且知道对方的存在和状态,为可靠的数据传输奠定基础。例如,当你使用浏览器访问一个网站时,浏览器与网站服务器之间会先建立 TCP 连接,然后才开始传输网页数据.
  • 可靠性高:TCP 协议通过多种机制来确保数据的准确无误传输。它使用确认机制,接收方在收到数据后会向发送方发送确认消息,发送方只有在收到确认后才会继续发送下一部分数据,否则会重传未确认的数据。同时,TCP 还具备重传机制,对于在传输过程中丢失或损坏的数据,发送方会自动重新发送,直到数据被正确接收。此外,流量控制和拥塞控制也是 TCP 保证可靠性的重要手段,它可以根据网络状况和接收方的处理能力,动态调整数据传输的速率,避免网络拥塞导致数据丢失.
  • 数据有序:TCP 会对数据进行编号和排序,确保数据按照发送的顺序到达接收端。即使数据在网络中经过不同的路径传输,到达接收端时也会被正确地重组,保证应用程序能够接收到完整、有序的数据。例如,在文件传输过程中,文件的各个部分会按照顺序依次传输并在接收端正确拼接。
  • 适用于多种应用:由于其可靠性高,TCP 适用于对数据准确性要求严格的应用场景,如文件传输(FTP)、电子邮件(SMTP、POP3 等)、远程登录(Telnet)、网页浏览(HTTP、HTTPS)等,这些应用需要确保数据的完整性和准确性,不容许数据丢失或出错。

UDP(User Datagram Protocol,用户数据报协议)

  • 无连接:UDP 在发送数据之前不需要与接收方建立连接,发送方可以随时向目标地址发送数据报。这使得 UDP 的传输过程更加简单、快速,减少了连接建立和拆除的开销1.
  • 不可靠传输:UDP 不提供数据传输的可靠性保证,它不会对数据进行确认、重传或排序等操作。数据报在网络中可能会出现丢失、重复或乱序的情况,并且 UDP 本身不会对这些问题进行处理,而是由应用层来负责处理数据的可靠性问题。不过,在一些对实时性要求较高但对数据准确性要求相对较低的应用中,这种不可靠性是可以接受的,例如在线游戏中的玩家位置信息更新、视频会议中的语音和视频数据传输等,偶尔丢失一两个数据包不会对整体效果产生太大影响1.
  • 低延迟:由于不需要建立连接和进行复杂的可靠性控制,UDP 的传输延迟相对较低,能够快速地将数据发送到目标地址。这对于实时性要求高的应用非常有利,如音频流、视频流等实时多媒体应用,可以在保证一定流畅度的前提下,尽可能减少延迟1.
  • 高效性:UDP 协议的头部开销较小,只有 8 个字节,相比 TCP 的 20 个字节头部,UDP 可以在相同的网络带宽下传输更多的数据,提高了数据传输的效率1.
  • 适用于特定应用:UDP 常用于一些对实时性和效率要求较高,但对数据可靠性要求相对较低的应用场景,如网络视频会议、在线游戏、音频流播放、实时监控等。例如,在网络视频会议中,即使偶尔丢失一些视频帧,也不会对会议的进行产生严重影响,而较低的延迟可以保证参会者之间的交互更加流畅。

 四、网络字节序 

1、判断是小端还是大端 小权重放到小地址就是小端(小小小)

大端:数据的高位字节存于低地址,低位字节存于高地址。 

程序:判断机器是大端还是小端?

#include <stdio.h>
int main() {int num = 0x12345678;char *ptr = (char *)&num;if (*ptr == 0x78) {printf("Little - Endian\n");} else if (*ptr == 0x12) {printf("Big - Endian\n");} else {printf("Error\n");}return 0;
}

2、网络规定都是大端 ,低地址高字节

五、UDP客户端服务器通信 

步骤:1、创建UDP套接字 下面为创建套接字的接口 socket         

第一个参数表示的是使用的协议家族,域到底是什么,第二个表示定义的套接字类型,流,还是数据报,第三个参数表示协议参数,填0就行

返回值 On success, a file descriptor for the new socket is returned.  On error, -1 is returned, and errno is set appropriately. 

           2、绑定 bind

插入:如何快速地将整数ip转为字符串? 比如12345667转为0.0.36.123 ,我们经常用的就是点分十进制,但是我们要知道如何转换。有接口inet_addr

【0,255】.【0,255】.【0,255】.【0,255】

struct ip
{uint8_t part1;  //占一个字节uint8_t part2;uint8_t part3;uint8_t part4;
}
int src_ip=12345678;
struct ip *p=(struct ip*)src_ip; //由于 src_ip 是一个 32 位的整数,而 struct ip 是一个包含四个 uint8_t 类型字段的结构体,直接把 src_ip 赋值给 struct ip 类型的变量是不可能的(类型不兼容)。但是,通过指针,我们可以将 src_ip 的内存解释为 struct ip 类型,并按字节访问它。
to_string(p->part1)+"."+to_string(p->part2)+"."+to_string(p->part3)+"."+to_string(p->part4);就把四字节转换为字符串风格的ip
结果是0.0.3.182

字符串转整数 ”192.168.50.100“  ”192“ ”168“”50“”100“

//192.168.50.100 转换为 123455556
uint32_t Ip; 4个字节
struct ip* x=(struct ip*)&Ip;
x->part1=stoi("192");
x->part2=stoi("168");
x->part3=stoi("50");
x->part4=stoi("100");

查看服务器启动的命令:netstat -nau

 一个关于ip

云服务器禁止直接bind公网ip,一个机器可能有多个ip,bind(IP:0),IP为0叫做任意地址绑定凡是发给我这台主机的数据,我们都要根据端口号向上交付。 

 一个关于port

【0,1023】属于系统内定的端口号,一般都要有固定的应用层协议使用 http:80 https:443 mysql:3306 我们绑定1024以上的

结论:IP地址绑定0,端口号绑定1024以上的

六、程序实现

Log.hpp
#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}// void logmessage(int level, const char *format, ...)// {//     time_t t = time(nullptr);//     struct tm *ctime = localtime(&t);//     char leftbuffer[SIZE];//     snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),//              ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,//              ctime->tm_hour, ctime->tm_min, ctime->tm_sec);//     // va_list s;//     // va_start(s, format);//     char rightbuffer[SIZE];//     vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);//     // va_end(s);//     // 格式:默认部分+自定义部分//     char logtxt[SIZE * 2];//     snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);//     // printf("%s", logtxt); // 暂时打印//     printLog(level, logtxt);// }void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};// int sum(int n, ...)
// {
//     va_list s; // char*
//     va_start(s, n);//     int sum = 0;
//     while(n)
//     {
//         sum += va_arg(s, int); // printf("hello %d, hello %s, hello %c, hello %d,", 1, "hello", 'c', 123);
//         n--;
//     }//     va_end(s); //s = NULL
//     return sum;
// }
Main.cc
#include "UdpServer.hpp"
#include <memory>
#include "Log.hpp"
Log log;void Usage(std::string proc)
{std::cout<<"\n\rUsage:"<<proc<<"proc[1024+]"<<std::endl;
}
//./udpserver port
//"192.168.1.123"点分十进制字符串风格的ip地址,一共占了13个字节
int main(int argc,char *argv[])
{if(argc!=2){Usage(argv[0]);exit(0);}uint16_t port=std::stoi(argv[1]);  //字符串转整数std::unique_ptr<UdpServer> svr(new UdpServer());svr->Init();svr->Run();return 0;
}
Makefile
.PHONY:all
all:Udpserver Udpclient
Udpserver:Main.ccg++ -o $@ $^ -std=c++11
Udpclient:UdpClient.ccg++ -o $@ $^ -std=c++11
.PHONY:
clean: rm -f Udpserver Udpclient
Udpclient
#include<iostream>
#include<unistd.h>
#include<cstdlib>
#include<sys/types.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
using namespace std;
void Usage(std::string proc)
{std::cout<<"\n\rUsage:"<<proc<<"serverip serverport"<<std::endl;
}
// ./udpclient serverip serverport 启动客户端的时候,必须要是ip和端口号是是什么
int main(int argc,char* argv[])
{if(argc!=3){Usage(argv[0]);exit(0);}std::string serverip=argv[1];uint16_t serverport=std::stoi(argv[2]);//构建服务器信息struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());socklen_t len = sizeof(server);int sockfd=socket(AF_INET,SOCK_DGRAM,0);//client要绑定,要有自己的IP和端口,只不过不需要用户显示的bind,一般由os随机选择!肯定是客户端先向服务器发起请求,端口号能唯一标识客户端就行,随机分配,但是服务器的端口号必须要准确知道,不然客户端绑定哪一个//系统什么时候给我Bind,首次放松数据的时候就绑定,sendtostring message;char buffer[1024];//接收时候的bufferwhile(1){cout<<"Please Enter@";std::getline(cin,message);cout<<message<<endl;//1.数据 2.给谁发 &server 发送给serversendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,len);struct sockaddr_in temp;socklen_t len=sizeof(temp);//服务器发消息处理了之后,再给客户端发回来,客户端就要去接收ssize_t s=recvfrom(sockfd,buffer,1023,0,(struct sockaddr*)&temp,&len);  //倒数第二个是谁发的if(s>0){buffer[s]=0;}cout<<buffer<<endl;}close(sockfd);return 0;
};
Udpserver
#pragma once
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<string>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "Log.hpp"
extern Log log;
enum{SOCKET_ERR=1,BIND_ERR=2
};
uint16_t defaultport=8080;
std::string defaultip="0.0.0.0";
const int size=1024;
class UdpServer
{
public:UdpServer(const uint16_t &port=defaultport,const std::string &ip=defaultip):port_(port),sockfd_(0),ip_(ip),isrunning_(false)//一个服务器要启动起来,端口号要有,Ip地址也要有{}void Init(){sockfd_=socket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sockfd_<0){log(Fatal,"socket create error,sockfd:%d",sockfd_);exit(SOCKET_ERR);}printf("socket create success,sockfd:%d\n",sockfd_);log(Info,"socket create success,sockfd:%d",sockfd_);struct sockaddr_in local;bzero(&local,sizeof(local));//把结构体里面的内容全部清零 ,第二个参数是缓冲区的大小local.sin_family=AF_INET;local.sin_port=htons(port_); //我要给你发数据,你必须知道我的端口号,我要把我的端口号发给你,因此端口号是需要在网络中传输的,必须是网络字节序列//local.sin_addr.s_addr=inet_addr(ip_.c_str());  //1.string->uint32_t   将string转char* string.c_str()local.sin_addr.s_addr=INADDR_ANY;//0,任意绑定,因为是全0,主机转网络不需要做bind(sockfd_,(const struct sockaddr *)&local,sizeof(local));}//服务器应该周而复始的运行void Run(){isrunning_=true;char inbuffer[size];while (isrunning_){
//完成一次收和一次发struct sockaddr_in client;//客户端信息socklen_t len =sizeof(client);//从哪个套接字中读,读到的消息放到哪里,读多大,谁给发的,结构体大小ssize_t n=recvfrom(sockfd_,inbuffer,sizeof(inbuffer)-1,0,(sockaddr*)&client,&len);if(n<0){log(Warning,"recvform error");continue;}inbuffer[n]=0;//对字符串进行加工std::string info=inbuffer;std::string echo_string="server echo#"+info;//再把数据发送回给对方 string的长度  string.size//你本地的套接字;发送的字符串和长度;默认为0;输入性参数,我知道对方是谁,因为当时对方给我发过消息sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);}}~UdpServer(){if(sockfd_>0)  close(sockfd_);}
private:int sockfd_;//网络文件描述符uint16_t port_; //端口号是两个字节,16个比特位,服务器要有自己的端口号std::string ip_;//任意地址绑定,填为0bool isrunning_;
};

改进版:

Main.cc
#include "UdpServer.hpp"
#include <memory>
#include <cstdio>
#include "Log.hpp"
Log log;void Usage(std::string proc)
{std::cout<<"\n\rUsage:"<<proc<<"proc[1024+]"<<std::endl;
}
std::string Handler(const std::string &str)
{std::string res="Server get a message:";res+=str;return res;//服务器收到消息,回调式的调用你传进来的方法,把数进行加工,加工处理完后返回,最后把这个结果发出去
}
std::string ExecuteCommand(const std::string &cmd)
{// SafeCheck(cmd);FILE* fp=popen(cmd.c_str(),"r");if(nullptr==fp){perror("popen");return "error";}std::string result;//从fp中把命令执行结果都拿出来char buffer[4096];while(true){char * res=fgets(buffer,4096,fp);//读到一行if(nullptr==res) break;result+=buffer;}return result;pclose(fp);
}
//./udpserver port
//"192.168.1.123"点分十进制字符串风格的ip地址,一共占了13个字节
int main(int argc,char *argv[])
{if(argc!=2){Usage(argv[0]);exit(0);}uint16_t port=std::stoi(argv[1]);  //字符串转整数std::unique_ptr<UdpServer> svr(new UdpServer());svr->Init();svr->Run(ExecuteCommand);return 0;
}
Udpserver.hpp
#pragma once
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<string>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <functional>
#include "Log.hpp"
using func_t=std::function<std::string(const std::string&)>; //返回值为string,参数为const std::string&的函数传递给Udpserver
//等价于typedef std::function<std::string(const std::string&)> func_t;
extern Log log;
enum{SOCKET_ERR=1,BIND_ERR=2
};
uint16_t defaultport=8080;
std::string defaultip="0.0.0.0";
const int size=1024;
class UdpServer
{
public:UdpServer(const uint16_t &port=defaultport,const std::string &ip=defaultip):port_(port),sockfd_(0),ip_(ip),isrunning_(false)//一个服务器要启动起来,端口号要有,Ip地址也要有{}void Init(){sockfd_=socket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sockfd_<0){log(Fatal,"socket create error,sockfd:%d",sockfd_);exit(SOCKET_ERR);}printf("socket create success,sockfd:%d\n",sockfd_);log(Info,"socket create success,sockfd:%d",sockfd_);struct sockaddr_in local;bzero(&local,sizeof(local));//把结构体里面的内容全部清零 ,第二个参数是缓冲区的大小local.sin_family=AF_INET;local.sin_port=htons(port_); //我要给你发数据,你必须知道我的端口号,我要把我的端口号发给你,因此端口号是需要在网络中传输的,必须是网络字节序列//local.sin_addr.s_addr=inet_addr(ip_.c_str());  //1.string->uint32_t   将string转char* string.c_str()local.sin_addr.s_addr=INADDR_ANY;//0,任意绑定,因为是全0,主机转网络不需要做bind(sockfd_,(const struct sockaddr *)&local,sizeof(local));}//服务器应该周而复始的运行//这样的好处是实现代码的分层void Run(func_t func)//运行的时候需要用户传进来一个怎么处理数据的方法{isrunning_=true;char inbuffer[size];while (isrunning_){
//完成一次收和一次发struct sockaddr_in client;//客户端信息socklen_t len =sizeof(client);//从哪个套接字中读,读到的消息放到哪里,读多大,谁给发的,结构体大小ssize_t n=recvfrom(sockfd_,inbuffer,sizeof(inbuffer)-1,0,(sockaddr*)&client,&len);if(n<0){log(Warning,"recvform error");continue;}inbuffer[n]=0;std::string info=inbuffer;std::string echo_string =func(info);sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);}}~UdpServer(){if(sockfd_>0)  close(sockfd_);}
private:int sockfd_;//网络文件描述符uint16_t port_; //端口号是两个字节,16个比特位,服务器要有自己的端口号std::string ip_;//任意地址绑定,填为0bool isrunning_;
};

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案

手机实时提取SIM卡打电话的信令声音 --智能拨号器app的双SIM卡切换方案 一、前言 在蓝牙电话的方案中&#xff0c;由于采用市场上的存量手机来做为通讯呼叫的载体&#xff0c;而现在市面上大部分的手机都是“双卡双待单通”手机&#xff0c;简称双卡双待手机。即在手机开机后…

Spring Boot 同时接受文件和实体及 Postman 测试实战

Spring Boot 文件上传及 Postman 测试指南 在本文中&#xff0c;我们将介绍如何使用 Spring Boot 上传文件并通过 Postman 测试接口。我们会基于以下接口作为示例&#xff1a; Boolean importDevicePushConfig(RequestParam("file") MultipartFile file,DevicePush…

Paddle Inference部署推理(一)

一&#xff1a;Paddle Inference推理 简介 Paddle Inference 是飞桨的原生推理库&#xff0c;提供服务器端的高性能推理能力。由于 Paddle Inference 能力直接基于飞桨的训练算子&#xff0c;因此它支持飞桨训练出的所有模型的推理。 Paddle Inference 功能特性丰富&#xff…

搭建文件服务器并使用Qt实现文件上传和下载(带账号和密码)

文章目录 0 背景1 搭建文件服务器2 代码实现文件上传和下载2.1 在pro文件中添加网络支持2.2 创建网络管理类2.3 文件上传2.4 文件下载 3 扩展&#xff08;其他方法实现文件上传和下载&#xff09;3.1 python3.2 npm3.3 ftp服务器 4 完整的代码 0 背景 因为需要使程序具备在远程…

社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略

摘要&#xff1a;随着实体商业与社交网络深度融合&#xff0c;社交新零售蓬勃兴起&#xff0c;“21 链动模式 S2B2C 商城小程序”作为其中创新典范&#xff0c;融合独特激励机制与数字化运营优势&#xff0c;重塑零售生态。本文剖析该模式架构、运作逻辑&#xff0c;探讨其在私…

【Git】Git 完全指南:从入门到精通

Git 完全指南&#xff1a;从入门到精通 Git 是现代软件开发中最重要的版本控制工具之一&#xff0c;它帮助开发者高效地管理项目&#xff0c;支持分布式协作和版本控制。无论是个人项目还是团队开发&#xff0c;Git 都能提供强大的功能来跟踪、管理代码变更&#xff0c;并保障…

华为E9000刀箱(HWE9000V2)服务器硬件监控指标解读

随着数据中心规模的不断扩大&#xff0c;服务器的稳定性和可靠性变得尤为重要。华为E9000刀箱&#xff08;HWE9000V2&#xff09;作为一款高性能的服务器设备&#xff0c;其硬件状态的实时监控对于保障业务的连续性和系统的稳定运行至关重要。 监控易作为一款专业的IT基础设施监…

Css—实现3D导航栏

一、背景 最近在其他的网页中看到了一个很有趣的3d效果&#xff0c;这个效果就是使用css3中的3D转换实现的&#xff0c;所以今天的内容就是3D的导航栏效果。那么话不多说&#xff0c;直接开始主要内容的讲解。 二、效果展示 三、思路解析 1、首先我们需要将这个导航使用一个大…

gitee:删除仓库

1、点击主页面设置 2、找到左侧导航栏-数据管理->仓库空间信息&#xff1b;找到需要删除的仓库->点击设置 3、点击左侧仓库设置->点击右侧删除仓库 4、输入提示内容->确认删除 5、输入密码验证 6、成功删除提示

探索 Python 任务自动化的新境界:Invoke 库揭秘

文章目录 探索 Python 任务自动化的新境界&#xff1a;Invoke 库揭秘背景&#xff1a;为何选择 Invoke&#xff1f;什么是 Invoke&#xff1f;如何安装 Invoke&#xff1f;5个简单的库函数使用方法1. 定义任务2. 带参数的任务3. 运行 Shell 命令4. 任务参数化5. 列出任务 场景应…

深入理解计算机系统,源码到可执行文件翻译过程:预处理、编译,汇编和链接

1.前言 从一个高级语言到可执行程序&#xff0c;要经过预处理、编译&#xff0c;汇编和链接四个过程。大家可以思考下&#xff0c;为什么要有这样的过程&#xff1f; 我们学习计算机之处&#xff0c;就应该了解到&#xff0c;计算机能够识别的只有二进制语言&#xff08;这是…

六通道串口服务器

型号&#xff1a;SG-TCP232-620 1.1 功能 1.1.1 基本功能 串口服务器是串口 RS232/422/485 和以太网之间的一个转换器&#xff0c;实现串口数 据和以太网数据的双向透明传输&#xff0c;可以让串口设备立即联网&#xff0c;典型应用拓扑如下&#xff1a; 1.1.2 特色功能…

Ubuntu 18.04 中安装 RDKit(针对 Python 2.7)

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

websocket前后端长连接之java部分

一共有4个类,第一个WebSocketConfig 配置类 Configuration EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {Autowiredprivate WebSocketHandler webSocketHandler;Autowiredprivate WebSocketInterceptor webSocketInterceptor;Overridepubli…

PyCharm中Python项目打包并运行到服务器的简明指南

目录 一、准备工作 二、创建并设置Python项目 创建新项目 配置项目依赖 安装PyInstaller 三、打包项目 打包为可执行文件 另一种打包方式&#xff08;使用setup.py&#xff09; 四、配置服务器环境 五、上传可执行文件到服务器 六、在服务器上运行项目 配置SSH解释…

【UE5 C++课程系列笔记】05——组件和碰撞

效果 可以看到我们可以实现的功能是 &#xff08;1&#xff09;可以通过鼠标旋转视角 &#xff08;2&#xff09;通过使用Pawn移动组件来控制Pawn移动 &#xff08;3&#xff09;Pawn碰到物体会被阻挡然后逐渐滑动 &#xff08;4&#xff09;通过空格切换激活/关闭粒子效果…

格网法计算平面点云面积(matlab版本)

1、原理介绍 格网法计算平面点云面积&#xff0c;其思想类似高中油膜法计算面积。其将点云投影到水平面&#xff0c;再将点云划分成尺寸相同的格网。最后&#xff0c;统计格网内包含点的数量number&#xff0c;那么可利用如下公式计算得到点云的面积&#xff1a; Aeranumber*L…

ZooKeeper 基础知识总结

先赞后看&#xff0c;Java进阶一大半 ZooKeeper 官网这样介绍道&#xff1a;ZooKeeper 是一种集中式服务&#xff0c;用于维护配置信息、命名、提供分布式同步和提供组服务。 各位hao&#xff0c;我是南哥&#xff0c;相信对你通关面试、拿下Offer有所帮助。 ⭐⭐⭐一份南哥编写…

2024年第十三届”认证杯“数学中国数学建模国际赛(小美赛)

↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

ATTCK红队评估实战靶场(二)

http://vulnstack.qiyuanxuetang.net/vuln/?page2 描述&#xff1a;红队实战系列&#xff0c;主要以真实企业环境为实例搭建一系列靶场&#xff0c;通过练习、视频教程、博客三位一体学习。本次红队环境主要Access Token利用、WMI利用、域漏洞利用SMB relay&#xff0c;EWS re…