压测利器Webbench(附源码)

web压力测试工具webbench介绍

webbench最多可以模拟3万个并发连接去测试网站的负载能力,并发能力比较高,可以测试https及动态静态页面。

核心原理

父进程fork若干个子进程,每个子进程在用户要求时间或默认的时间内对目标web循环发出实际访问请求,父子进程通过管道进行通信,子进程通过管道写端向父进程传递在若干次请求访问完毕后记录到的总信息,父进程通过管道读端读取子进程发来的相关信息,子进程在时间到后结束,父进程在所有子进程退出后统计并给用户显示最后的测试结果,然后退出。

 编译安装

1.wget https://www.ha97.com/code/webbench-1.5.tar.gz
2.tar zxvf webbench-1.5.tar.gz
3.cd webbench-1.5
4.make
5.make install

 使用

1.webbench -c 1000 -t 30 baidu.com

参数说明:-c表示并发数,-t表示时间(s)

webbench [option]... URL-f|--force               Don't wait for reply from server.-r|--reload              Send reload request - Pragma: no-cache.-t|--time <sec>          Run benchmark for <sec> seconds. Default 30.-p|--proxy <server:port> Use proxy server for request.-c|--clients <n>         Run <n> HTTP clients at once. Default one.-9|--http09              Use HTTP/0.9 style requests.-1|--http10              Use HTTP/1.0 protocol.-2|--http11              Use HTTP/1.1 protocol.--get                    Use GET request method.--head                   Use HEAD request method.--options                Use OPTIONS request method.--trace                  Use TRACE request method.-?|-h|--help             This information.-V|--version             Display program version.

主要原理图

 

webbench 的主要压测流程:

1.解析参数:用户通过命令行参数指定目标网址、并发连接数、测试时长等参数。webbench 首先会解析这些参数,确定压测的目标和条件。
2.创建并发连接:webbench 根据用户指定的并发连接数,在测试开始时创建相应数量的并发连接。这些连接将模拟多个客户端同时访问目标网站。
3.建立连接:对于每个并发连接,webbench 发起一个 HTTP 请求并尝试与目标服务器建立连接。这些连接可能是非阻塞的,允许同时处理多个连接。
4.发送请求:一旦连接建立成功,webbench 就会向目标服务器发送 HTTP 请求。这些请求可以是简单的 GET 请求,也可以包含其他 HTTP 方法和自定义的请求头信息。
5.接收响应:webbench 在发送请求后会等待目标服务器的响应。它可以根据用户指定的超时时间来确定是否需要等待响应,或者在超时后放弃等待并关闭连接。
6.记录结果:在测试过程中,webbench 会记录每个请求的响应时间、状态码等信息。这些信息将用于后续的性能分析和结果报告。
7.重复测试:根据用户指定的测试时长,webbench 会在一定时间内不断重复发送请求和接收响应,以模拟持续的并发访问情况。
8.汇总结果:在测试结束后,webbench 会汇总所有请求的结果,并计算出一些统计信息,如平均响应时间、成功率等。这些信息将作为压测结果向用户展示。
9.生成报告:最后,webbench 会根据测试结果生成一份报告,包括压测的详细信息、性能指标和可能的改进建议。用户可以根据这份报告来评估服务器的性能表现和优化方向。

源码:

webbench.c

#include "socket.c"  
#include <unistd.h>  
#include <sys/param.h>  
#include <rpc/types.h>  
#include <getopt.h>  
#include <strings.h>  
#include <time.h>  
#include <signal.h> //统计的压力测试最终结果表示
volatile int timerexpired = 0;  
int speed = 0;  
int failed = 0;  
int bytes = 0;//http请求方法
#define METHOD_GET 0  
#define METHOD_HEAD 1  
#define METHOD_OPTIONS 2  
#define METHOD_TRACE 3  #define PROGRAM_VERSION "1.5"  // 默认设置:一般需用户自己传入命令行参数设置  
int method = METHOD_GET;    //默认请求方法为GET方式   
int clients = 1;            //默认只模拟一个客户端  
int force = 0;              //默认需要等待服务器响应
int force_reload = 0;       //失败时重新请求   
int proxyport = 80;         //默认访问服务器端口为80 
char *proxyhost = NULL;     //默认无代理服务器  
int benchtime = 30;         //默认模拟请求时间为30s  // globals 版本号 
int http10 = 1;   //0:- http/0.9, 1:- http/1.0, 2:- http/1.1 int mypipe[2];             //管道用于父子进程通信
char host[MAXHOSTNAMELEN]; //存储服务器网络地址  
#define REQUEST_SIZE 2048  
char request[REQUEST_SIZE]; //存放http请求报文信息数组//函数声明 
static void benchcore(const char* host,const int port, const char *request);  
static int bench(void);  
static void build_request(const char *url); // 用法与各参数详细含义 
static void usage(void)  
{  fprintf(stderr,  "webbench [option]... URL\n"       //用法"  -f|--force               Don't wait for reply from server.\n"  "  -r|--reload              Send reload request - Pragma: no-cache.\n"  "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"  "  -p|--proxy <server:port> Use proxy server for request.\n"  "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"  "  -9|--http09              Use HTTP/0.9 style requests.\n"  "  -1|--http10              Use HTTP/1.0 protocol.\n"  "  -2|--http11              Use HTTP/1.1 protocol.\n"  "  --get                    Use GET request method.\n"  "  --head                   Use HEAD request method.\n"  "  --options                Use OPTIONS request method.\n"  "  --trace                  Use TRACE request method.\n"  "  -?|-h|--help             This information.\n"  "  -V|--version             Display program version.\n"  );  
};  //结构体数组:每一个元素格式为:{长选项,选项后是否带有参数,int*指针(为NULL),对应短选项或
static const struct option long_options[]=                  //不为NULL,将第四个参数值给第三个参数} 
{  {"force",no_argument,&force,1},  {"reload",no_argument,&force_reload,1},  {"time",required_argument,NULL,'t'},  {"help",no_argument,NULL,'?'},  {"http09",no_argument,NULL,'9'},  {"http10",no_argument,NULL,'1'},  {"http11",no_argument,NULL,'2'},  {"get",no_argument,&method,METHOD_GET},    {"head",no_argument,&method,METHOD_HEAD},  {"options",no_argument,&method,METHOD_OPTIONS},  {"trace",no_argument,&method,METHOD_TRACE},  {"version",no_argument,NULL,'V'},  {"proxy",required_argument,NULL,'p'},  {"clients",required_argument,NULL,'c'},  {NULL,0,NULL,0}  
};  int main(int argc, char *argv[])  
{  int opt = 0;  int options_index = 0;  char *tmp = NULL;  //一、检验命令行参数//1.不带选项时直接输出用法help信息if(argc == 1)  {  usage();  return 2;  }  //2.带选项时则解析命令行参数并根据传入选项进行相关设置// getopt_long 为命令行解析的库函数,根据argc来寻找(argv,"912Vfrt:p:c:?h")这两个字符串匹配的选项,//如果是短选项,则直接返回这个选项给opt,//如果是长选项,则到option long_options[]结构体数组中寻找匹配其长选项,返回其对应的短选项给opt,//若其第三个参数不为NULL,将第四个参数值给第三个参数,并且返回0给opt//此函数自带全局变量://optarg:指向选项后的参数:-t 100,指向100;//optind: 当前访问到的argv索引值//opterr: 其值非0时,代表有无效选项,缺少参数,输出错误信息//optopt: 发现无效选项时,函数返回“? / :”,将其值设为无效选项字符while((opt = getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options/*结构体数组指针*/,&options_index)) != EOF )  {   switch(opt)    //根据返回值判断用户传入的参数进行相关设置{  case  0 : break;  case 'f': force = 1;break;        //force=1代表不等待服务器响应 case 'r': force_reload = 1;break; //发送重新加载请求 case '9': http10 = 0;break;  case '1': http10 = 1;break;  case '2': http10 = 2;break;  case 'V':  printf(PROGRAM_VERSION"\n");  exit(0);  case 't':  benchtime = atoi(optarg);   //设置用户传入的运行时间 break;  case 'c': clients = atoi(optarg);     //设置创建的客户端数break;  case 'p':  //使用代理服务器,设置其代理网络号和端口号:格式:-p server:port tmp = strrchr(optarg,':');   //查找“:”在optarg中最后一次出现的位置    proxyhost = optarg;       //设置网络号if(tmp == NULL)  //没有:号,没有端口号{  break;  }  if(tmp == optarg)    //端口号在首位置,错误:缺失主机名{  fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);  return 2;  }  if(tmp == optarg + strlen(optarg)-1) //:号在末位,缺少端口号  {  fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);  return 2;  }  *tmp = '\0';  //将:号置为“\0”proxyport = atoi(tmp+1);  //设置新的端口号 break;  case ':':  case 'h':  case '?': usage();return 2;break; }  } //getopt_long函数将选项解析完成后,读到url不会在读取,此时argv[optind]指向url//optind 被 getopt_long设置为命令行参数中未读取的下一个元素下标值 if(optind == argc) //若相等即没有输入URL {  fprintf(stderr,"webbench: Missing URL!\n");  usage();  return 2;  }  //若客户端选项后参数设为0,则更改 if(clients == 0) clients = 1;  if(benchtime == 0) benchtime = 60;  //输出webbench版本相关信息  fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n"  "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n"  );  //二、构造HTTP请求到request数组build_request(argv[optind]);   //传入URL//http请求构造成功后//以下输出提示信息  printf("\nBenchmarking: ");    //测压开始switch(method)     //用的请求方法{  case METHOD_GET:  default:  printf("GET");break;  case METHOD_OPTIONS:  printf("OPTIONS");break;  case METHOD_HEAD:  printf("HEAD");break;  case METHOD_TRACE:  printf("TRACE");break;  }  printf(" %s",argv[optind]);   //访问的url switch(http10)    //http协议版本号{  case 0: printf(" (using HTTP/0.9)");break;  case 2: printf(" (using HTTP/1.1)");break;  }  printf("\n");  //模拟连接客户端数目if(clients == 1) printf("1 client");  else  printf("%d clients",clients);  //连接测试的时间printf(", running %d sec", benchtime); if(force) printf(", early socket close");//输出代理服务器的信息    if(proxyhost != NULL) printf(", via proxy server %s:%d",proxyhost,proxyport); if(force_reload) printf(", forcing reload");  printf(".\n");  //开始压力测试,返回 bench 函数执行结果  return bench();  
}  //二、构造HTTP请求到request数组
void build_request(const char *url)  
{  char tmp[10];  int i;  //初始化 bzero(host,MAXHOSTNAMELEN);  bzero(request,REQUEST_SIZE);  //判断应该使用的 HTTP 协议  if(force_reload && proxyhost != NULL && http10 < 1) http10 = 1;  if(method == METHOD_HEAD && http10 < 1) http10 = 1;  if(method == METHOD_OPTIONS && http10 < 2) http10 = 2;  if(method == METHOD_TRACE && http10 < 2) http10 = 2;  //1.填写http请求第一行//填写请求方法methodswitch(method)  {  default:  case METHOD_GET: strcpy(request,"GET");break;  case METHOD_HEAD: strcpy(request,"HEAD");break;  case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;  case METHOD_TRACE: strcpy(request,"TRACE");break;  }  strcat(request," ");  //URL 合法性判断  //若没有"://"则不合法if(NULL == strstr(url,"://")){  fprintf(stderr, "\n%s: is not a valid URL.\n",url);  exit(2);  }  //若url过长非法if(strlen(url)>1500)  {  fprintf(stderr,"URL is too long.\n");  exit(2);  }  if(proxyhost == NULL)   //若无代理服务器 {       if(0 != strncasecmp("http://",url,7)) //忽略大小写比较 {  //只支持 HTTP 地址  fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");  exit(2);  } }       //找到主机名开始的地方:如:http://baidu.com:80/  i = strstr(url,"://")-url+3;   //i==7// 必须以 / 结束  if(strchr(url+i,'/')==NULL) //在字符串中寻找“/” ,找不到则非法URL{  fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");  exit(2);  }  if(proxyhost == NULL)  //若无代理服务器 {  // 得到端口号从主机名if(index(url+i,':') != NULL && index(url+i,':') < index(url+i,'/'))  //若带有端口号,index函数与strchr相似{  //设置网络号strncpy(host,url+i,strchr(url+i,':')-url-i);    //如将baidu.com拷贝到host数组里即网络地址//初始化 bzero(tmp,10);  strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1); //将端口号拷贝到tmp数组中 //设置端口  proxyport = atoi(tmp);  if(proxyport==0) proxyport=80;  } else   //没有端口号,直接拷贝域名到host数组中{  strncpy(host,url+i,strcspn(url+i,"/"));  //strcspn找url+i到“/”之间的字符个数 }    //将资源路径填入请求行里strcat(request+strlen(request),url+i+strcspn(url+i,"/")); } else    //若有代理服务器{  strcat(request,url);  //直接填入URL到请求行中}  //填入http版本号到请求行中if(http10 == 1)  strcat(request," HTTP/1.0");  else if (http10==2)  strcat(request," HTTP/1.1");  strcat(request,"\r\n");  //2.填请求报头:NAME:VALUEif(http10 > 0)  strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");  if(proxyhost == NULL && http10 > 0)  {  strcat(request,"Host: ");  strcat(request,host);  strcat(request,"\r\n");  }  if(force_reload && proxyhost != NULL)  {  strcat(request,"Pragma: no-cache\r\n");  }  if(http10 > 1)  strcat(request,"Connection: close\r\n");  //3.填入空行  if(http10>0) strcat(request,"\r\n");  //构造完成
} static int bench(void)   //父进程做的工作
{  int i,j,k;  pid_t pid = 0;  FILE *f;  //建立网络连接 :先测试一次,服务器是否可以正常连接成功   i = Socket(proxyhost == NULL ? host:proxyhost, proxyport);  if(i < 0){  fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");  return 1;  }  close(i);   //测试成功,一次连接完成关闭//建立管道通信  if(pipe(mypipe))  {  perror("pipe failed.");  return 3;  }  //派生子进程进行压力测试 :传入多少个客户端则建立多少个子进程进行连接 for(i = 0;i < clients;i++)  {  pid = fork();  if(pid <= (pid_t)0)  {  sleep(1);break;     //使子进程立刻跳出循环,要不就子进程继续 fork 了}  } //子进程创建失败if( pid < (pid_t)0)   {  fprintf(stderr,"problems forking worker no. %d\n",i);  perror("fork failed.");  return 3;  } //子进程执行if(pid == (pid_t)0)   {  //子进程发出实际请求   if(proxyhost == NULL)  benchcore(host,proxyport,request);  else  benchcore(proxyhost,proxyport,request);  // 打开管道写:连接请求状态的信息 f = fdopen(mypipe[1],"w"); //将文件描述符转换为文件指针 if(f == NULL)  {  perror("open pipe for writing failed.");  return 3;  }  //写入f文件中此进程在一定时间中请求成功的次数,失败的次数,读取服务器回复的总字节数  fprintf(f,"%d %d %d\n",speed,failed,bytes);  fclose(f);  return 0;  } else {  //父进程打开管道读   f = fdopen(mypipe[0],"r");  if(f == NULL)  {  perror("open pipe for reading failed.");  return 3;  }  setvbuf(f,NULL,_IONBF,0);  //设置f的缓冲区为无缓冲区speed = 0;   //连接成功总次数    failed = 0;  //失败请求数  bytes = 0;   //传输字节数 while(1)  {  pid = fscanf(f,"%d %d %d",&i,&j,&k);  if(pid<2)  {  fprintf(stderr,"Some of our childrens died.\n");  break;  } speed += i;   //连接成功总次数 failed += j;  //连接失败总次数bytes += k;   //传输总字节数//子进程是否读取完  if(--clients == 0) break;  }  fclose(f);  //统计结果计算 printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",  (int)((speed+failed)/(benchtime/60.0f)),   //总连接次数/总时间=每分钟请求连接次数   (int)(bytes/(float)benchtime),     //每秒传输字节数speed,                             //连接成功次数failed);                           //连接失败次数}  return i;  
}  //信号处理函数 
static void alarm_handler(int signal)  
{  timerexpired = 1;  
}  //子进程处理发起请求
void benchcore(const char *host,const int port,const char *req)  
{  int rlen;  char buf[1500];  int s,i;  struct sigaction sa;  //安装信号sa.sa_handler = alarm_handler;  sa.sa_flags = 0;  if(sigaction(SIGALRM,&sa,NULL))  exit(3);  //设置闹钟函数 alarm(benchtime);  rlen = strlen(req);  nexttry:  while(1){  //收到信号则使 timerexpired = 1   if(timerexpired)  {  if(failed > 0)  {  failed--;  }  return;  }  //建立 socket连接, 进行 HTTP 请求   s = Socket(host,port);  if(s < 0)  {  failed++;  //连接失败则++ continue;  }  if(rlen!=write(s,req,rlen))  {  failed++;  //写失败++close(s);  continue;  }  //HTTP 0.9 的处理 if(http10==0)  // 如果关闭不成功   if(shutdown(s,1)) //关闭连接写一半 {  failed++;  close(s);  continue;  }  // -f 选项时未设置时等待读取服务器回复   if(force == 0)  {  while(1)  {  if(timerexpired)break;  i = read(s,buf,1500);  if(i<0)  {  failed++;     //读失败++close(s);  goto nexttry;  }  else  if(i == 0)   //读完退出break;  else bytes+=i;  //统计服务器回复的字节数 }  }  if(close(s))  {  failed++;  //关闭失败++continue;  }  speed++;   //成功连接一次++一次}  
}     

socket.c

#include <sys/types.h>  
#include <sys/socket.h>  
#include <fcntl.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>  
#include <sys/time.h>  
#include <string.h>  
#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <stdarg.h>  int Socket(const char *host, int clientPort)  
{  int sock;  unsigned long inaddr;  struct sockaddr_in ad;  struct hostent *hp;  // 初始化地址 memset(&ad, 0, sizeof(ad));  ad.sin_family = AF_INET;  // 尝试把主机名转化为数字  inaddr = inet_addr(host);  if (inaddr != INADDR_NONE)  memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));  else  {  // 取得 ip 地址  hp = gethostbyname(host);    //得到主机的二进制Ip给hp->h_addr if (hp == NULL)  return -1;  memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);  }  ad.sin_port = htons(clientPort);  // 建立 socket  sock = socket(AF_INET, SOCK_STREAM, 0);  if (sock < 0)  return sock;  // 建立链接   if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)  return -1; return sock;  
}  

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

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

相关文章

C#打印50*30条码标签

示例图&#xff1a; 源码下载地址&#xff1a;https://download.csdn.net/download/tiegenZ/89035407?spm1001.2014.3001.5503

01背包和完全背包

文章目录 01背包1、01背包暴力解法&#xff0c;回溯问题2、动态规划解法3、01背包代码优化 完全背包1、完全背包模型 GitHub参考链接 01背包 1、01背包暴力解法&#xff0c;回溯问题 #include<bits/stdc.h> using namespace std; const int N 1e25; int w[N],v[N]; i…

ValueError: Cannot load file containing pickled data when allow_pickle=False

问题描述 遇到报错&#xff1a;ValueError: Cannot load file containing pickled data when allow_pickleFalse 解决方案 经过查阅有人说是与numpy的版本有关&#xff0c;但是还是不要轻易改变环境中的版本&#xff0c;不一定哪个地方就会报错。这里放个解决方案&#xff1a;…

C++生成动态连接库

文章目录 一、静态连接与动态连接二、 动态链接库&#xff08;DLL&#xff09;的创建三、dll库的使用四、 动态链接链接库工作原理五、extern "C" 一、静态连接与动态连接 静态库和动态库区别是库的加载时间不同。静态库&#xff1a;在链接阶段库将会与.o目标文件一起…

YOLO中的预训练模型是否需要

这张图片显示的是使用YOLOv5&#xff08;一种流行的物体检测算法&#xff09;进行训练时的一段命令行指令以及对应的注释&#xff0c;这些注释是中文的。这里列出的是两个不同情况下的命令行用法。 上面的命令&#xff1a; python train.py --data custom.yaml --weights yolo…

C++中的凸包:convexHull使用手册【c++重要方法】

最近工作中&#xff0c;用到了凸包&#xff0c;查了一些资料&#xff0c;差不多搞明白了&#xff0c;在这里做一个总结&#xff0c;希望可以帮助到你&#xff01; 什么时候需要它&#xff1f; 如果你想要把一群散落的点&#xff0c;包裹起来。而且希望这个包裹尽可能地紧凑&a…

MQTT.fx和MQTTX 链接ONENET物联网提示账户或者密码错误

参考MQTT.fx和MQTTX 链接ONENET物联网开发平台避坑细节干货。_mqttx和mqttfx-CSDN博客 在输入password和username后还是提示错误&#xff0c;是因为在使用token的时候&#xff0c;key填写错误&#xff0c;将设备的密钥填入key中

How to convert .py to .ipynb in Ubuntu 22.04

How to convert .py to .ipynb in Ubuntu 22.04 jupyter nbconvertp2j 最近看到大家在用jupyter notebook&#xff0c;我也试了一下&#xff0c;感觉还不错&#xff0c;不过&#xff0c;也遇到了一些问题&#xff0c;比方说&#xff0c;我有堆的.py文件&#xff0c;如果要一个一…

赛氪网亮相中国人工智能产业发展联盟会议,共筑赛事生态新篇章

2024年3月14日至15日&#xff0c;备受瞩目的中国人工智能产业发展联盟&#xff08;AIIA&#xff09;第十一次全体会议在海南海口盛大召开。作为人工智能领域的重要交流与合作平台&#xff0c;此次会议吸引了300余位联盟成员单位代表齐聚一堂&#xff0c;共襄盛举。在这场人工智…

NIO与AIO

NIO与AIO NIO模型 在 LInux 环境中&#xff0c;java.nio.channels.Selector 的子类叫做 sun.nio.ch.EPollSelectorImpl &#xff0c;其底 层是基于 Epoll 模型去实现的 IO 多路复用器。 对于 Epoll 模型 我们需要了解到它底层的三个函数 在 JDK 实现的底层中&#xff0c;EPol…

某对象存储元数据集群改造流水账

软件产品&#xff1a;某厂商提供的不便具名的对象存储产品&#xff0c;核心底层技术源自HDFS和Amazon S3&#xff0c;元数据集群采用了基于MongoDB的NOSQL数据库产品和MySQL数据库产品相结合。 该产品的元数据逻辑示意图如下&#xff1a; 业务集群现状&#xff1a;当前第3期建…

勾八头歌之分类回归聚类

一、机器学习概述 第1关机器学习概述 B AD B BC 第2关常见分类算法 #编码方式encodingutf8from sklearn.neighbors import KNeighborsClassifierdef knn(train_data,train_label,test_data):input:train_data用来训练的数据train_label用来训练的标签test_data用来测试的数据…

【Monero】Onion Monero Blockchain Explorer | 洋葱门罗币区块链浏览器

github&#xff1a;onion-monero-blockchain-explorer Onion Monero Blockchain Explorer特点: • 没有cookie&#xff0c;没有网络分析跟踪器&#xff0c;没有image&#xff0c; • 开源&#xff0c; • 完全用C编写&#xff0c; • 显示加密的付款 ID&#xff0c; • 显示环…

Django auth模块

【一】命令行创建用户 【1】语法 python manage.py createsuper【2】示例 用户名 默认是是电脑名称 邮箱 可以填也可以不填 密码 terminal中&#xff1a;输入密码不显示出来manage.py中&#xff1a;明文输入输入密码太简单会提示 Username (leave blank to use administra…

20231911 2022-2023-2 《网络攻防实践》实验三

1.实验内容 1、实践tcpdump 使用tcpdump开源软件对在本机上访问www.tianya.cn网站过程进行嗅探&#xff0c;回答问题&#xff1a;你在访问www.tianya.cn网站首页时&#xff0c;浏览器将访问多少个Web服务器&#xff1f;他们的IP地址都是什么&#xff1f; 2、实践Wireshark 使…

Cesium for UE-03-添加数据集(倾斜摄影)

继续上一章节&#xff0c;在创建了项目和关卡的基础上添加倾斜摄影 重新打开上次的项目和关卡 如果你已经关掉了上次的项目和关卡&#xff0c;可以重新打开ue&#xff0c;然后选择 选择 文件-打开关卡&#xff0c;在弹出的窗口中&#xff0c;选择 上次的关卡&#xff0c;并点击…

从汇编以及栈帧层面理解内联函数的原理

宏太复杂&#xff0c;所以弄出内联&#xff0c;内联适合小函数&#xff0c;把函数连到程序里面&#xff0c;这样就直接用&#xff0c;不需要调用&#xff0c;但是它占用空间。 C推荐 const和enum替代宏常量 inline去替代宏函数 宏缺点&#xff1a; 1、不能调试 2、没有类型安…

多层感知机-----自我神经MLP入门笔记

多层感知机&#xff08;Multilayer Perceptron, MLP&#xff09;是一种常见的人工神经网络&#xff08;Artificial Neural Network, ANN&#xff09;模型&#xff0c;它由多个人工神经元组成的多层结构。每个神经元都与前一层的所有神经元连接&#xff0c;并且每条连接都有一个…

HarmonyOS(鸿蒙开发)入门篇

如果需要学习鸿蒙开发可以查看以下学习资源链接 OpenAtom OpenHarmony Develop applications - HUAWEI HarmonyOS APP 转载请注明出处HarmonyOS(鸿蒙开发&#xff09;入门篇-CSDN博客&#xff0c;谢谢&#xff01;