编写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算法思想 …...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...