编写HTTP协议代理的一些知识(源码)
初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
早期上网经常需要使用代理服务器,现在用的比较少了,大家更耳熟能详的反而是“反向代理”如Nginx。
代理服务器一般用作局域网上网,而反向代理则是把来自互联网的连接转发到局域网上,作用刚好相反。
HTTP协议自身就带有对代理服务器的支持。HTTP协议目前主要有多个版本,0.9太简单,基本不见了,1.0只支持一个连接一个请求,1.1则支持长连接,2.0极大复杂化了传输过程,支持多路复用。协议版本这么多,但是代理服务器作为中间商,可以选择一个较低的版本,用户的客户端和服务器一般都有能力适应多个版本。
代理服务器可以选择比较简单的HTTP1.0版本,一个连接就是一个请求,只需要在连接建立之后做处理,处理完请求就是简单的数据转发了。
目录
HTTP1.0协议对代理服务器的支持基本就是两点:
代理服务器要做的事情是:
代理服务器认证
隧道请求CONNECT
代码示例
HTTP1.0协议对代理服务器的支持基本就是两点:
- 请求行对使用绝对URL
- 专用于代理服务器的Proxy-XXXX头标
代理服务器要做的事情是:
- 取出请求行的服务器域名和端口并擦除(擦除后与直接请求的请求行相同)
- 将协议版本降低为自己支持的版本
- 根据proxy-XXXX头标处理并擦除
- 像直接请求一样访问服务器
- 转发数据给用户
前面说的“擦除”是把后面的数据前移而不是设置为空格,设置为空格并不符合HTTP协议,服务器一般不能理解。
原则上代理服务器可以支持客户端和服务器是不同的协议版本,比如客户端是1.0而服务器是1.1,这将极大地影响程序复杂度。
虽然HTTP的BODY与代理服务器处理无关,只需要接受完头部就可以处理,但是最好整个请求完整发送,因为有些服务器不能处理请求头和BODY分开的情形。
代理服务器认证
代理服务器通过Proxy-XXXX头标进行认证,这个认证是代理服务器的认证而不是用户要访问的服务器的认证。代理服务器认证完后就应该删除这些头标,因为这些头标对目标服务器毫无意义。
隧道请求CONNECT
CONNECT是个不常用的头标,专门用于代理。代理服务器取得目标服务器后直接连上去就可以了,然后就是双向转发数据。
代码示例
下面的代码就是一个HTTP1.0代理的协议处理部分的代码,没有认证(因为用的是IP地址认证,在进入这个代码之前就已经处理过了):
//servicethreadhttp.cpp#include "stdafx.h"
#include "mystd.h"
#include "Proxy.h"
#include "httpresp.h"extern CProxyApp theApp;//HTTP协议处理线程
DWORD ServiceThreadHttp(LPDWORD lpdwParam)
{
//--线程参数处理------------------------int cdindex;//连接数据索引struct ServiceData * servicedata;cdindex=((struct ThreadUserData *)lpdwParam)->index;servicedata=((struct ThreadUserData *)lpdwParam)->servicedata;
//--------------------------------------struct ConnectionData * cd;struct LogStruct * logs;cd=&servicedata->connectiondataarray.pconnectiondata[cdindex];if(-1!=cd->log){logs=servicedata->memlogfile.logstruct+cd->log;}else{logs=NULL;}
//----------------------------------------struct ConfigInfo * pci;pci=&servicedata->serviceconfigfiledata.configarray[cd->serviceindex];int headlen;int port;char host[256];char uri[256];unsigned long addr;SOCKADDR_IN sa;BOOL isTunnel=FALSE;//是否是隧道请求char tunnelresponse[]="HTTP/1.0 200 Connection established\x0d\x0a""Proxy-agent: FreeProxy 1.0\x0d\x0a\x0d\x0a";//退出?if(CONNECTIONDATA_CMD_QUIT==cd->cmd){closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//接收请求cd->sdc.bufcount=RecvHttpRequest(cd->sdc.s,cd->sdc.buf,BUFFERSIZE,&cd->cmd,&headlen,pci->islimitpost,1000*pci->maxpost);if(0>cd->sdc.bufcount){//DebugMessage("RecvHttpRequest失败");closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//分析请求
/* char tracertfile[256];if(-1!=mymemindex(cd->sdc.buf,cd->sdc.bufcount,"says=%2Fnick",strlen("says=%2Fnick"))){strcpy(tracertfile,"tracert_");itoa(cdindex,tracertfile+strlen(tracertfile),10);if(-1!=cd->log)WriteTracertFile(tracertfile,logs->username,strlen(logs->username));WriteTracertFile(tracertfile,cd->sdc.buf,cd->sdc.bufcount);}*/if(0>GetHttpURL(cd->sdc.buf,&cd->sdc.bufcount,headlen+4,host,256,&port,uri,256)){if(pci->isenableconnect && 0<=GetTunnelURL(cd->sdc.buf,&cd->sdc.bufcount,headlen+4,host,256,&port,uri,256)){//是隧道请求isTunnel=TRUE;if(-1!=cd->log){strcpy(logs->domainname,host);}}else{send(cd->sdc.s,httpresp400,strlen(httpresp400),0);closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-2;}}else{if(-1!=cd->log){strcpy(logs->domainname,host);}}ClearProxyInfo(cd->sdc.buf,&cd->sdc.bufcount);//检查目标许可if(IsForbidden(&theApp.bandata,host,uri)){send(cd->sdc.s,httpresp403,strlen(httpresp403),0);closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//退出?if(CONNECTIONDATA_CMD_QUIT==cd->cmd){closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//记录日志,计时开始if(-1!=cd->log){time(&logs->timestart);}//域名解析if(1!=GetAddrByHost(addr,host)){send(cd->sdc.s,httpresp600,strlen(httpresp600),0);closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-3;}memcpy(&(sa.sin_addr.S_un.S_addr),&addr,4);sa.sin_family=AF_INET;sa.sin_port=htons((unsigned short)port);//建立SOCKETif(INVALID_SOCKET==(cd->sdr.s=socket(AF_INET,SOCK_STREAM,0))){send(cd->sdc.s,httpresp601,strlen(httpresp601),0);closesocket(cd->sdc.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-4;}//退出?if(CONNECTIONDATA_CMD_QUIT==cd->cmd){closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//连接if(SOCKET_ERROR==connect(cd->sdr.s,(struct sockaddr *)&sa,sizeof(sa))){send(cd->sdc.s,httpresp602,strlen(httpresp602),0);closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-5;}else{if(-1!=cd->log){strcpy(logs->domainname,uri);}}//退出?if(CONNECTIONDATA_CMD_QUIT==cd->cmd){closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//发送请求if(isTunnel){if(SOCKET_ERROR==send(cd->sdc.s,tunnelresponse,strlen(tunnelresponse),0)){send(cd->sdc.s,httpresp603,strlen(httpresp603),0);closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-6;}}if(SOCKET_ERROR==send(cd->sdr.s,cd->sdc.buf,cd->sdc.bufcount,0)){send(cd->sdc.s,httpresp603,strlen(httpresp603),0);closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-6;}//记录字节数if(-1!=cd->log){logs->bytecount+=cd->sdc.bufcount;}///TraceData(servicedata->isDataTrace,&servicedata->memlogfile.logdatatrace[cd->log].dc,cd->sdc.buf,cd->sdc.bufcount);//退出?if(CONNECTIONDATA_CMD_QUIT==cd->cmd){closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){logs->state=LOGSTRUCT_STATE_NOUSE;}cd->state=CONNECTION_NOUSE;return (DWORD)-1;}//接收数据并发给客户TransData(cd->sdr.s,cd->sdc.s,cd->sdr.buf,BUFFERSIZE,&cd->cmd,&cd->sdr.bufcount,servicedata,cd);//记录字节数if(-1!=cd->log){logs->bytecount+=cd->sdr.bufcount;}closesocket(cd->sdc.s);closesocket(cd->sdr.s);if(-1!=cd->log){time(&logs->timeend);logs->state=LOGSTRUCT_STATE_USED;}cd->state=CONNECTION_NOUSE;return 1;
}//接收HTTP请求(如果出错,不执行closesocket())
int RecvHttpRequest(SOCKET s,char * buf,int buflen,int * cmd,int* headlen,BOOL islimitpost,int maxpost)
{maxpost+=1;const char CRLF[]="\x0d\x0a";const char CRLFCRLF[]="\x0d\x0a\x0d\x0a";const char CONTENTLENGTH[]="Content-Length:";int recvcount=0;int temp;int recvall=0;BOOL tempbool;struct timeval timeout;timeout.tv_sec=0;timeout.tv_usec=100000;for(;1;){//退出?if(CONNECTIONDATA_CMD_QUIT==*cmd){return -1;}if(1!=IsSocketReadReady(s,timeout,tempbool)){return -2;}if(tempbool){recvcount=recv(s,buf+recvall,buflen-recvall,0);}else{continue;}if(SOCKET_ERROR==recvcount){return -3;}else if(0==recvcount){return -4;}recvall+=recvcount;//在使用后面代码段时使用CRLFCRLF,4,否则使用CRLF,2temp=mymemindex(buf,recvall,(char*)CRLFCRLF,4);if(-1!=temp){*headlen=temp;break;}}if(islimitpost && -1!=(temp=mymemindex(buf,*headlen,(char*)CONTENTLENGTH,15))){long i;char len[10];if(-1==(i=mymemindex(buf+temp,buflen-temp,(char*)CRLF,2))){return -5;}i-=strlen(CONTENTLENGTH);if(i>9){return -6;}memcpy(len,buf+temp+strlen(CONTENTLENGTH),i);len[i]='\0';i=atoi(len);if(i>maxpost){return -7;}}return recvall;
}//取得URL
int GetHttpURL(char* buf,int * buflenall,int buflen,char * host,int hostbuflen,int * port,char * uri,int uribuflen)
{const char CRLF[]="\x0d\x0a";int urlstart,urlend;int hoststart,hostend,hostlen;int portstart,portend,portlen;int pos;char str[10];urlend=mymemindex(buf,buflen,(char*)CRLF,2);if(-1==(urlstart=mymemindex(buf,urlend,"http://",7))){return -2; }if(urlend-urlstart>=uribuflen){memcpy(uri,buf+urlstart,uribuflen-1);uri[uribuflen-1]='\0';}else{memcpy(uri,buf+urlstart,urlend-urlstart);uri[urlend-urlstart]='\0';}//得到主机名起始位置hoststart=urlstart+7;if(-1==(pos=mymemindex(buf+hoststart,urlend-hoststart,"/",1))){return -3;}portend=pos+hoststart;pos=mymemindex(buf+hoststart,portend-hoststart,":",1);if(-1!=pos)//有端口{portstart=pos+hoststart+1;//得到端口起始位置hostend=pos+hoststart;portlen=portend-portstart;memcpy(str,buf+portstart,portlen);str[portlen]='\0';if(0==portlen) *port=80;//若端口长度为零,实际上无端口{if(0==(*port=atoi(str)))return -4;}}else//无端口{*port=80;hostend=portend;}hostlen=hostend-hoststart;if(hostlen>=hostbuflen)return -5;memcpy(host,buf+hoststart,hostlen);host[hostlen]='\0';//HTTP请求处理long i;//降版本1.1为1.0if('1'==buf[urlend-1]){buf[urlend-1]='0';}//擦去URLi=portend-urlstart;memmove(buf+urlstart,buf+portend,*buflenall-portend);*buflenall-=i;return hostlen;
}//取得隧道请求
int GetTunnelURL(char* buf,int * buflenall,int buflen,char * host,int hostbuflen,int * port,char * uri,int uribuflen)
{const char CRLF[]="\x0d\x0a";int urlstart,urlend;int hoststart,hostend,hostlen;int portstart,portend,portlen;int pos;char str[10];urlend=mymemindex(buf,buflen,(char*)CRLF,2);if(buflen<8 || 0!=memcmp(buf,"CONNECT",7))return -2;if(' '!=buf[7])return -2;for(urlstart=8;urlstart<buflen;urlstart++){if(' '!=buf[urlstart])break;}if(urlend>=uribuflen){memcpy(uri,buf,uribuflen-1);uri[uribuflen-1]='\0';}else{memcpy(uri,buf,urlend);uri[urlend]='\0';}//得到主机名起始位置hoststart=urlstart;if(-1==(pos=mymemindex(buf+hoststart,urlend-hoststart,"/",1))){return -3;}portend=pos+hoststart;pos=mymemindex(buf+hoststart,portend-hoststart,":",1);if(-1!=pos)//有端口{portstart=pos+hoststart+1;//得到端口起始位置hostend=pos+hoststart;portlen=portend-portstart;memcpy(str,buf+portstart,portlen);str[portlen]='\0';if(0==portlen) *port=80;//若端口长度为零,实际上无端口{if(0==(*port=atoi(str)))return -4;}}else//无端口{*port=80;hostend=portend;}hostlen=hostend-hoststart;if(hostlen>=hostbuflen)return -5;memcpy(host,buf+hoststart,hostlen);host[hostlen]='\0';//HTTP请求处理*buflenall=0;return hostlen;
}//清除代理信息
int ClearProxyInfo(char * buf,int * buflenall)
{const char PROXYCONNECTION[]="Proxy-Connection";const char CRLF[]="\x0d\x0a";int i,j;if(2>(i=mymemindex(buf,*buflenall,PROXYCONNECTION,strlen(PROXYCONNECTION))))return 1;//前面至少应有一个CRLFif(0!=memcmp(buf+i-2,CRLF,2))return 1;if(-1==(j=mymemindex(buf+i+strlen(PROXYCONNECTION),(*buflenall)-i-strlen(PROXYCONNECTION),CRLF,2))){j=(*buflenall)-i-strlen(PROXYCONNECTION);}//擦去代理信息memmove(buf+i-2,buf+i+strlen(PROXYCONNECTION)+j,(*buflenall)-(i+strlen(PROXYCONNECTION)+j));*buflenall-=2+strlen(PROXYCONNECTION)+j;return 1;
}
主要就是这么几件事:取出目标地址和端口,擦除目标信息,降低版本为1.0,擦除Proxy-XXXX头标,连接目标,双向转发数据。
这个代码是从实际项目中截取出来的。
(这里是结束)
相关文章:
编写HTTP协议代理的一些知识(源码)
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 早期上网经常需要使用代理服务…...

LabVIEW天然气压缩因子软件设计
LabVIEW天然气压缩因子软件设计 项目背景 天然气作为一种重要的能源,其压缩因子的准确计算对于流量的计量和输送过程的优化具有关键意义。传统的计算方法不仅步骤繁琐,而且难以满足现场快速响应的需求。因此,开发一款既能保证计算精度又便于…...

GCP谷歌云有什么数据库类型,该怎么选择
GCP谷歌云提供的数据库类型主要包括: 关系型数据库:这类数据库适用于结构化数据,通常用于数据结构不经常发生变化的场合。在GCP中,关系型数据库选项包括Cloud SQL和Cloud Spanner。Cloud SQL提供托管的MySQL、PostgreSQL和SQL Se…...

项目经理之路:裁员与内卷下的生存策略
作为一名项目经理,身处这个充满挑战与机遇的行业中,今年所面临的裁员潮和内卷化趋势无疑给我的工作带来了前所未有的压力。然而,正是这些压力和挑战,让我们更加深刻地思考了在这个快速变化的时代中,我们项目经理应该如…...

MWM触摸屏工控机维修TEM-EV0 EN00-Z312yy-xx
触摸屏维修是一个比较复杂的过程,并且其中会涉及到各个部件的问题,这对于操作人员来说,关键在于是否可以找到问题所在。维修过程中建议先检查各接线接口是否出现松动,然后检查串口及中断号是否有冲突,若有冲突…...

idm下载到99.99%不动了 idm突然不下载了 idm下载到最后没速度咋办 IDM下载后没网了是怎么回事
idm能够帮助我们下载不同类型的网页视频,并且基于多线程下载技术的助力下使其下载速度比原来提升数倍以上,因此成为了许多朋友下载的小助手。但也有朋友反映idm下载网页视频超时连接不上,idm下载网页视频突然停止,究竟这些情况我们…...
设计模式-07 设计模式-观察者模式(Observer Pattern)
设计模式-07 设计模式-观察者模式(Observer Pattern) 1.定义 观察者模式是一种软件设计模式,它定义了一种一对多的依赖关系,其中一个对象(称为“主题”)维护了一个依赖对象的列表(称为“观察者”…...

戒烟网站|基于SSM+vue的戒烟网站系统的设计与实现(源码+数据库+文档)
戒烟网站 目录 基于SSM+vue的戒烟网站系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1网站功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主…...

研发管理之认识DevOps
文章目录 一、什么是DevOps二、DevOps的背景和起源三、DevOps的特点和价值1、特点:2、价值: 四、DevOps如何帮助提高软件交付速度和质量 一、什么是DevOps DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称…...

Spring MVC(五) 文件上传
1 单文件上传 在程序开发中,有时候需要上传一些文件。我们在学习Servlet的时候,也做过文件上传的操作,只不过基于Servlet的文件上传操作起来过于复杂,因此所有的MVC框架都提供了自己的文件上传操作,基本上都是基于File…...
Redis——Redis数据分片的三种算法
Redis的数据分片通常是为了实现水平扩展,将数据分散到多个Redis节点上,以提高系统的容量和性能。在Redis的不同实现和集群方案中,数据分片的算法有所不同。以下是Redis数据分片的三种常见算法: 哈希取模分片(Hash Modu…...

【专利】一种日志快速分析方法、设备、存储介质
公开号CN116560938A申请号CN202310311478.5申请日2023.03.28 是我在超音速人工智能科技股份有限公司(833753) 职务作品,第一发明人是董事长夫妇,第二发明人是我。 ** 注意** : 内容比较多,还有流程图、界面等。请到 专利指定页面…...

HFSS学习-day5-边界条件
边界条件 概述边界条件类型1、理想导体边界条件(Perfect E)2、理想磁边界条件(Perfect H)3、有限导体边界条件(Finite Conductivity)4、辐射边界条件(Radiation)5、对称边界条件&…...
spring Aop使用示例
简介(aop作用):1.在不改变源代码的基础上进行功能添加,如日志打印、执行时间统计。2.与代理效果类似但更加便捷。 示例: maven依赖: <dependency><groupId>org.springframework</groupId&g…...

MySQL-InnoDB数据存储结构
1、存储结构-页 索引结构提供了高效的索引方式,索引信息以及数据记录都保存在数据文件或索引文件中(本质存储在页结构中) 1.1、磁盘与内存交互的基本单位:页 在InnoDB中将数据划分为若干页,页的默认大小为ÿ…...

【吊打面试官系列】Java高并发篇 - 什么是 Java Timer 类?如何创建一个有特定时间间隔的任务?
大家好,我是锋哥。今天分享关于 【什么是 Java Timer 类?如何创建一个有特定时间间隔的任务?】面试题,希望对大家有帮助; 什么是 Java Timer 类?如何创建一个有特定时间间隔的任务? java.util.T…...
Spring生命周期深度解析
Spring生命周期深度解析 介绍 Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的、非侵入式的开发方式,使得开发者可以更加专注于业务逻辑的实现,而不必过多关注底层的技术细节。 在使用Spring框架开发应用程序时…...

基于 Windows 的记事本简单功能开发及部署发布--迭代2.0
基于上篇文章基于 Windows 的记事本简单功能开发-CSDN博客 更新完成以下几个功能点: 1.中心部件更改为栅格布局 2.另存为功能: 打开文本保存框,用户选中文件保存时 得到绝对路径。 判断用户选择路径不为空。 得到用户输入内容。 创建文件对象&…...

Java lambda
forEach 比 for 语句的线程安全要求更严格。 如此语句使用for语句可以,但是forEach却不可以。...

【智能算法】河马优化算法(HO)原理及实现
目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年,MH Amiri受到自然界河马社会行为启发,提出了河马优化算法(Hippopotamus Optimization Algorithm, HO)。 2.算法原理 2.1算法思想 …...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found
Nginx1.24编译时,报LuaJIT2.x错误, configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT 2.x ... not…...
十二、【ESP32全栈开发指南: IDF开发环境下cJSON使用】
一、JSON简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有以下核心特性: 完全独立于编程语言的文本格式易于人阅读和编写易于机器解析和生成基于ECMAScript标准子集 1.1 JSON语法规则 {"name"…...