基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpRequest模块 解析http请求协议
一、HTTP响应报文格式
HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xf3c9743300024ee4
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 26 Feb 2021 08:44:35 GMT
Expires: Fri, 26 Feb 2021 08:44:35 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=13; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33514_33257_33273_31660_33570_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1614329075128412289017566699583927635684
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
二、根据解析出的原始数据,对客户端的请求做出处理 processHttpRequest
// 处理http请求协议
bool processHttpRequest(struct HttpRequest* req,struct HttpResponse* response);
// 处理基于get的http请求
bool processHttpRequest(struct HttpRequest* req,struct HttpResponse* response) {if(strcasecmp(req->method,"get") != 0) {return -1;}decodeMsg(req->url,req->url); // 解码字符串// 处理客户端请求的静态资源(目录或者文件)char* file = NULL;if(strcmp(req->url,"/") == 0) {file = "./";}else {file = req->url + 1;}// 获取文件属性struct stat st;int ret = stat(file,&st);if(ret == -1) {// 文件不存在 -- 回复404// sendHeadMsg(cfd,404,"Not Found",getFileType(".html"),-1);// sendFile("404.html",cfd);strcpy(response->fileName,"404.html");response->statusCode = NotFound;strcpy(response->statusMsg,"Not Found");// 响应头httpResponseAddHeader(response,"Content-Type",getFileType(".html"));response->sendDataFunc = sendFile;return 0;}strcpy(response->fileName,file);response->statusCode = OK;strcpy(response->statusMsg,"OK!");// 判断文件类型if(S_ISDIR(st.st_mode)) {// 把这个目录中的内容发送给客户端// sendHeadMsg(cfd,200,"OK",getFileType(".html"),-1);// sendDir(file,cfd);// 响应头httpResponseAddHeader(response,"Content-Type",getFileType(".html"));response->sendDataFunc = sendDir;}else {// 把文件的内容发送给客户端// sendHeadMsg(cfd,200,"OK",getFileType(file),st.st_size);// sendFile(file,cfd);// 响应头char tmp[12] = {0};sprintf(tmp,"%ld",st.st_size);httpResponseAddHeader(response,"content-type",getFileType(file));httpResponseAddHeader(response,"content-length",tmp);response->sendDataFunc = sendFile;}return 0;
}
1.解码字符串
- 解决浏览器无法访问带特殊字符的文件得到问题
// 将字符转换为整型数
int hexToDec(char c){if (c >= '0' && c <= '9')return c - '0';if (c >= 'a' && c <= 'f')return c - 'a' + 10;if (c >= 'A' && c <= 'F')return c - 'A' + 10;return 0;
}// 解码字符串
// to 存储解码之后的数据, 传出参数, from被解码的数据, 传入参数
void decodeMsg(char* to,char* from) {for(;*from!='\0';++to,++from) {// isxdigit -> 判断字符是不是16进制格式, 取值在 0-f// Linux%E5%86%85%E6%A0%B8.jpgif(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2])){// 将16进制的数 -> 十进制 将这个数值赋值给了字符 int -> char// B2 == 178// 将3个字符, 变成了一个字符, 这个字符就是原始数据// *to = (hexToDec(from[1]) * 16) + hexToDec(from[2]);*to = (hexToDec(from[1]) << 4) + hexToDec(from[2]);// 跳过 from[1] 和 from[2] ,因此在当前循环中已经处理过了from += 2;}else{// 字符拷贝,赋值*to = *from;}}*to = '\0';
}
2.判断文件扩展名,返回对应的 Content-Type(Mime-Type)
const char* getFileType(const char* name);
const char* getFileType(const char* name) {// a.jpg a.mp4 a.html// 自右向左查找 '.' 字符,如不存在返回NULLconst char* dot = strrchr(name,'.');if(dot == NULL) return "text/plain; charset=utf-8";//纯文本if(strcmp(dot,".html") == 0 || strcmp(dot,".htm") == 0) return "text/html; charset=utf-8";if(strcmp(dot,".jpg")==0 || strcmp(dot,".jpeg")==0) return "image/jpeg";if(strcmp(dot,".gif")==0)return "image/gif";if(strcmp(dot,".png")==0)return "image/png";if(strcmp(dot,".css")==0) return "text/css";if(strcmp(dot,".au")==0)return "audio/basic";if(strcmp(dot,".wav")==0)return "audio/wav";if(strcmp(dot,".avi")==0)return "video/x-msvideo";if(strcmp(dot,".mov")==0 || strcmp(dot,".qt")==0)return "video/quicktime";if(strcmp(dot,".mpeg")==0 || strcmp(dot,".mpe")==0)return "video/mpeg";if(strcmp(dot,".vrml")==0 || strcmp(dot,".wrl")==0)return "model/vrml";if(strcmp(dot,".midi")==0 || strcmp(dot,".mid")==0)return "audio/midi";if(strcmp(dot,".mp3")==0)return "audio/mpeg";if(strcmp(dot,".ogg") == 0) return "application/ogg";if(strcmp(dot,".pac") == 0)return "application/x-ns-proxy-autoconfig";if(strcmp(dot,".pdf") == 0)return "application/pdf";return "text/plain; charset=utf-8";//纯文本
}
3.发送文件 sendFile
// 发送文件
void sendFile(const char* fileName,struct Buffer* sendBuf,int cfd);
void sendFile(const char* fileName,struct Buffer* sendBuf,int cfd) {// 打开文件int fd = open(fileName,O_RDONLY);assert(fd > 0);
#if 1while (1) {char buf[1024];int len = read(fd,buf,sizeof(buf));if(len > 0) {// send(cfd,buf,len,0);bufferAppendData(sendBuf,buf,len);}else if(len == 0) {break;}else{close(fd);perror("read");}}
#else// 把文件内容发送给客户端off_t offset = 0;int size = lseek(fd,0,SEEK_END);// 文件指针移动到了尾部lseek(fd,0,SEEK_SET);// 移动到文件头部while (offset < size){int ret = sendfile(cfd,fd,&offset,size - offset);printf("ret value: %d\n",ret);if (ret == -1 && errno == EAGAIN) {printf("没数据...\n");}}
#endifclose(fd);
}
4.发送目录
// 发送目录
void sendDir(const char* dirName,struct Buffer* sendBuf,int cfd);
void sendDir(const char* dirName,struct Buffer* sendBuf,int cfd) {char buf[4096] = {0};sprintf(buf,"<html><head><title>%s</title></head><body><table>",dirName);struct dirent** nameList;int num = scandir(dirName,&nameList,NULL,alphasort);for(int i=0;i<num;i++) {// 取出文件名 nameList 指向的是一个指针数组 struct dirent* tmp[]char* name = nameList[i]->d_name;struct stat st;char subPath[1024] = {0};sprintf(subPath,"%s/%s",dirName,name);stat(subPath,&st);if(S_ISDIR(st.st_mode)) {// 从当前目录跳到子目录里边,/sprintf(buf+strlen(buf),"<tr><td><a href=\"%s/\">%s</a></td><td>%ld</td></tr>",name,name,st.st_size);}else{sprintf(buf+strlen(buf),"<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>",name,name,st.st_size);}// send(cfd,buf,strlen(buf),0);bufferAppendString(sendBuf,buf);memset(buf,0,sizeof(buf));free(nameList[i]); } sprintf(buf,"</table></body></html>");// send(cfd,buf,strlen(buf),0);bufferAppendString(sendBuf,buf);free(nameList);
}
三、解析http请求协议 parseHttpRequest
可以看这篇关于httpResponsePrepareMsg函数具体是如何组织响应数据的:HttpResponse的定义和初始化 以及组织 HttpResponse 响应消息https://blog.csdn.net/weixin_41987016/article/details/135464760
// 解析http请求协议
bool parseHttpRequest(struct HttpRequest* req,struct Buffer* readBuf,struct HttpResponse* response,struct Buffer* sendBuf,int socket);
// 解析http请求协议
bool parseHttpRequest(struct HttpRequest* req,struct Buffer* readBuf,struct HttpResponse* response,struct Buffer* sendBuf,int socket) {bool flag = true;while(req->curState!=ParseReqDone) {switch(req->curState) {case ParseReqLine:// 解析请求行flag = parseHttpRequestLine(req,readBuf);break;case ParseReqHeaders:// 解析请求头flag = parseHttpRequestHeader(req,readBuf);break;case ParseReqBody:break;default:break;}if(!flag) {return flag;}// 判断是否解析完毕了,如果完毕了,需要准备回复的数据if(req->curState==ParseReqDone) {// 1.根据解析出的原始数据,对客户端的请求做出处理processHttpRequest(req,response);// 2.组织响应数据并发送给客户端httpResponsePrepareMsg(response,sendBuf,socket);}}req->curState = ParseReqLine;// 状态还原,保证还能继续处理第二条及以后的请求return flag;
}
相关文章:

基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpRequest模块 解析http请求协议
一、HTTP响应报文格式 HTTP/1.1 200 OK Bdpagetype: 1 Bdqid: 0xf3c9743300024ee4 Cache-Control: private Connection: keep-alive Content-Encoding: gzip Content-Type: text/html;charsetutf-8 Date: Fri, 26 Feb 2021 08:44:35 GMT Expires: Fri, 26 Feb 2021 08:44:35 GM…...

muduo网络库剖析——网络地址InetAddress类
muduo网络库剖析——网络地址InetAddress类 前情从muduo到my_muduo 概要socketaddr_in介绍成员用法 网络地址转换函数 框架与细节成员函数使用方法 源码结尾 前情 从muduo到my_muduo 作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足&…...
什么是本地IP?服务器本地IP有哪些优势?
本地IP是指直接在互联网上分配给服务器或设备的IP地址,而不是通过NAT(网络地址转换)或 代理等中间设备进行转发。让我们关注本地IP的优势。 1.直接访问:原始IP允许无中间设备转发或代理直接访问服务器或设备。这减少了网络延迟&a…...

Open CASCADE学习|参数化球面的奇异性
参数曲面的奇异性是一个相对复杂的概念,它涉及到参数曲面的几何特性和参数化过程中的一些特殊情况。参数曲面通常用于描述三维空间中的复杂形状,通过参数方程将二维参数域映射到三维空间中。然而,在某些情况下,参数曲面可能会表现…...

基础知识篇(一)Acticity生命周期
Activity 类是 Android 应用的关键组件,而 activity 的启动和组合方式是平台应用模型的基本组成部分。与使用 main() 方法启动应用的编程范式不同,Android 系统会通过调用与其生命周期特定阶段对应的特定回调方法,在 Activity 实例中启动代码…...

Java内存结构
前文: 《Java8之类的加载》 《Java8之类加载机制class源码分析》 写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数…...

Java--ListUtil工具类,实现将一个大列表,拆分成指定长度的子列表
文章目录 前言实现代码执行结果 前言 在项目中有时会出现列表很大,无法一次性批量操作,我们需要将列表分成指定大小的几个子列表,一份一份进行操作,本文提供这样的工具类实现这个需求。 实现代码 以下为ListUtil工具类代码实现…...
SpringSecurity 密码加密登录
SpringSecurity 密码加密登录 1.前端所需文件2.后端所用工具类3.登录代码4.灵魂一问 1.前端所需文件 import JSEncrypt from jsencrypt/bin/jsencrypt.min// 密钥对生成 http://web.chacuo.net/netrsakeypairconst publicKey MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqz…...

大模型实战作业03
大模型实战作业03 注: 因为微调数据较少,没有显示出个人助手的名字...

【AI视野·今日Sound 声学论文速览 第四十四期】Tue, 9 Jan 2024
AI视野今日CS.Sound 声学论文速览 Tue, 9 Jan 2024 Totally 27 papers 👉上期速览✈更多精彩请移步主页 Daily Sound Papers DJCM: A Deep Joint Cascade Model for Singing Voice Separation and Vocal Pitch Estimation Authors Haojie Wei, Xueke Cao, Wenbo Xu…...
Windows Copilot 更新及使用教程
Windows Copilot 是一款由微软开发的人工智能辅助工具,可以通过学习用户的操作习惯和上下文,自动完成代码编写和其他重复性任务。它可以帮助开发人员提高工作效率,减少重复劳动。 以下是关于Windows Copilot的更新和使用教程的一些信息&…...

【Android开发】不同Activity之间的数据回传实例(一)摘桃子游戏
一、功能介绍 该项目实现的功能主要有: 在首页显示一个按钮点击该按钮跳转到桃园页面在桃园页面,点击桃子会弹窗显示摘到几个桃子,同时被点击桃子消失,总桃子数1点击退出桃园会返回首页,首页桃子数会根据点击的桃子数…...

增量式PID和脉冲轴组合控制阀门开度(算法介绍)
这篇博客我们以S7-1200PLC平台来举例,介绍我们的PID闭环控制器如何控制脉冲轴实现阀门角度控制。SMART PLC PID控制器控制伺服驱动器实现关节角度控制详细内容请参考下面文章: https://rxxw-control.blog.csdn.net/article/details/129658364https://rxxw-control.blog.csdn…...
解决Vue.js Devtools未检测到Vue实例的问题
解决Vue.js Devtools未检测到Vue实例的问题 解决Vue.js Devtools未检测到Vue实例的问题1. 确保Vue.js已正确加载1.1 在HTML文件中直接引入1.2 在构建工具(如Webpack)中配置引入1.3 检查与验证 2. 检查Vue.js Devtools扩展安装状态2.1 打开Chrome浏览器扩…...
【Java基础】进程与线程,并发与并行,CPU单核与多核
目录 1 进程与线程2 CPU单核与多核 1 进程与线程 进程与线程基本单位的对象不同 进程是操作系统进行资源分配(包括cpu、内存、磁盘IO等)的最小单位线程是CPU调度和分配的基本单位 CPU看不到进程,只能看到待分配的一些线程 并发与并行 并发&…...

git修改最新提交(commit)信息
一、修改最近一次commit信息 1、首先通过git log查看commit信息 2、使用命令git commit --amend进入命令命令模式,按i进入编辑模式,修改好commit信息后按Esc键退出编辑模式,然后输入:wq保存编辑信息(注意使用英文输入法…...

想寻找Axure的替代品?我们已经试用了10+款设计工具,来看看吧!
Axure是许多产品经理和设计师进入快速原型设计的首选工具,但Axure的使用成本相对较高,学习曲线陡峭,许多设计师正在寻找可以取代Axure的原型设计工具,虽然现在有很多可选的设计工具,但质量不均匀,可以取代A…...

报文大小限制、请求体类型总结
文章目录 1. 各节点请求体有无限制1.1 http协议1.2 TCP/IP层限制1.3 浏览器1.4 nginx1.5 gateway1.6 tomcat1.7 springboot1.8 内存、磁盘处理不了一切白搭 2. 请求体类型2.1 application/x-www-form-urlencoded2.2 multipart/form-data2.3 application/json2.4 text/plain2.5 …...
rknn加载onnx时报错 GLIBC=2.29 no found librknnc.so
rknn 中onnx转rknn在虚拟机中运行时发现报错. GLIBC2.29 no found /****/librknnc.so 昨天还正常的, 今天装了个ftp 和宝塔面板就出错了. 我估计根据报错地址, 找到了librknnc.so文件, 权限也给了777仍然不行 , 我怀疑是GLIBC的版本不对 ,网上给的方法是下载源码, 然后自己手动…...

ASP .net core微服务实战(杨中科)
背景: 主要是思考下,我们为什么要用微服务? 微服务我现在理解是:提供了我们一种模块化的手段,一个服务负责一种类型的业务,是一种面对复杂问题进行拆分的方式,但是也会引入一些中间件…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...