网络学习-利用reactor实现http请求(六)
一、实现HTTP请求
1、印象里面,总有人说C/C++语言不能实现HTTP请求,其实不然。C/C++语言完全可以实现HTTP请求。通过对select,poll,epoll等IO多路复用技术的学习以及reactor模式的学习,完全能够实现HTTP请求。
2、webserver
主要解决两个问题
1、请求数据
2、响应,回发数据
3、简单小测试
/***向服务器发送HTTP请求*/
int Http_Request(Conne *c)
{cout<<"Http_Request:"<<c->rbuffer<<endl;return 0;
}/*** 处理HTTP响应*/
int Http_Response(Conne *c)
{cout<<"Http_Response:"<<c->wbuffer<<endl;return 0;
}/*在reactor的那一套回调函数的基础上,添加接收到请求数据后,调用Http_Request,在回发数据之前,调用下Http_Response*/
int Recv_cb(int fd)
{int count = recv(fd, conn_poll[fd].rbuffer, BUFFER_SIZE, 0);if (count == 0){cout << "client close" << endl;close(conn_poll[fd].fd); // 关闭客户端的连接描述epoll_ctl(fd, EPOLL_CTL_DEL, conn_poll[fd].fd, NULL); // 将客户端的连接描述符从epoll实例中删除return 0;}cout << "recv_buffer:" << conn_poll[fd].rbuffer << endl;Http_Request(&conn_poll[fd]); //接收到数据后,进行解析请求数据conn_poll[fd].wlen = count;memcpy(conn_poll[fd].wbuffer, conn_poll[fd].rbuffer, count);SetEvent(fd, EPOLLOUT,0); //监听可写事件return count;
}int Send_cb(int fd)
{Http_Response(&conn_poll[fd]); // 在回发数据之间,响应数据,解析响应数据// 返回信息int count = send(fd, conn_poll[fd].wbuffer, conn_poll[fd].wlen, 0);SetEvent(fd, EPOLLIN,0); //监听可读事件return count;
}
客户端连接:
浏览器连接:
4、可以看到连接成功,但浏览器这边空空如也,添加点东西
int Http_Response(Conne *c)
{time_t t = time(NULL);struct tm *local_time = localtime(&t);c->wlen = sprintf(c->wbuffer, "HTTP/1.1 200 OK\r\n""Content-Type: text/html; charset=UTF-8\r\n""Accept-Ranges: bytes\r\n""Content-Length: 82\r\n""Date: %s\r\n""<html><head><title>Hello</title></head><body><h1>LengYa</h1></body></html>\r\n", ctime(&t));return 0;
}
5、C/C++里面写标签,太麻烦了,换成html文件,直接读取文件内容。
int Http_Response(Conne *c)
{time_t t = time(NULL);struct tm *local_time = localtime(&t);int filefd = open("index.html", O_RDONLY);struct stat stat_buf;fstat(filefd, &stat_buf);c->wlen = sprintf(c->wbuffer, "HTTP/1.1 200 OK\r\n""Content-Type: text/html; charset=UTF-8\r\n""Accept-Ranges: bytes\r\n""Content-Length: %ld\r\n""Date: %s\r\n", stat_buf.st_size,ctime(&t));int count = read(filefd, c->wbuffer + c->wlen, BUFFER_SIZE-c->wlen);c->wlen += count;close(filefd);return 0;
}
6、压力测试
工具准备:wrk
#c:连接
#t:线程
#d:持续时间
./wrk -c 10 -t 2 -d 30s http://192.168.127.132:2000/
结果:
在30.07s内,总共发送了168276个请求,总共读取91.47MB数据;平均每秒发送5595.89个请求,平均每秒读取3.04MB数据。
7、小结
通过上面的测试,可以发现,C/C++语言完全可以实现HTTP请求。只不过相对于专门处理web的java,c#,php等语言,在处理HTTP请求上,显得笨拙了些。
毕竟C/C++在处理业务逻辑上,不是强项,在处理底层,性能调优上才是强项。
二、拓展
1、请求图片数据
之前请求的html文本数据,而且数据量不大,这次换下个数据量大的,比如图片。
int filefd = open("test.jpg", O_RDONLY); // 打开文件struct stat stat_buf;
fstat(filefd, &stat_buf);c->wlen = sprintf(c->wbuffer, "HTTP/1.1 200 OK\r\n""Content-Type: image/jpeg; charset=UTF-8\r\n" //请求类型"Accept-Ranges: bytes\r\n""Content-Length: %ld\r\n""Date: %s\r\n", stat_buf.st_size,ctime(&t));
可以发现,图片数据量很大,基本没加载出来,毕竟代码中写的缓冲区大小就只有1024字节,远远不够。
如果要加载完图片,有两种思路:
1、增大缓冲区大小,让其足够大。
但多少才算是足够大呢,每次发现不够,需要重新修改代码,内测倒是可以,上线的话就麻烦了。
所以这个方法,不推荐。
2、分段发送,每次只发一小部分。
每次只发送一小部分,直到全部发送完毕。
/*
原来设置1024的缓冲区大小,如果数据量为10*1024字节,可以设置缓冲区大小为10*1024
也可以不必变更原来的大小,循环10次,每次发送1024字节,也能达到同样的效果
*/
/*
accept_cb----->Recv_cb----->Send_cb----->recv_cb----->Send_cb---->...
IO连接成功----->接收部分数据----->回发部分数据---->接收部分数据----->回发部分数据---->...---->数据全部接收完毕--->全部数据发送完毕
如何让其自动循环接收,发送数据,可以使用循环,通过计算文件大小,除以缓冲区大小,计算出需要循环的次数。
也可以设置状态,让其自动循环接收,发送数据。
*/
int status; //0--发送头,1--发送body,2--关闭连接//Http请求中初始化状态
int Http_Request(Conne *c)
{cout<<"Http_Request:"<<c->rbuffer<<endl;memset(c->rbuffer, 0, BUFFER_SIZE);c->wlen = 0;c->status = 0;return 0;
}//Http响应中,根据状态机,分段发送数据
int Http_Response(Conne *c)
{time_t t = time(NULL);struct tm *local_time = localtime(&t);int filefd = open("test.jpg", O_RDONLY);struct stat stat_buf;fstat(filefd, &stat_buf);if(c->status == 0){c->wlen = sprintf(c->wbuffer, "HTTP/1.1 200 OK\r\n""Content-Type: image/jpeg; charset=UTF-8\r\n""Accept-Ranges: bytes\r\n""Content-Length: %ld\r\n""Date: %s\r\n", stat_buf.st_size,ctime(&t));c->status = 1;}else if(c->status == 1){int ret = sendfile(c->fd, filefd, NULL, stat_buf.st_size); //数据拷贝if(ret < 0){ //出错处理cout << "sendfile error:" << strerror(errno) << endl;return -1;}c->status = 2; //发送完成,不再继续发送文件内容(防止重复发送}else if(c->status == 2){c->wlen = 0;memset(c->wbuffer, 0, BUFFER_SIZE); //清空缓冲区,防止重复发送c->status = 0; //发送完成,重置状态机}close(filefd);return 0;
}
int Send_cb(int fd)
{Http_Response(&conn_poll[fd]);// 返回信息int count = 0;if (conn_poll[fd].status == 1){count = send(fd, conn_poll[fd].wbuffer, conn_poll[fd].wlen, 0);SetEvent(fd, EPOLLOUT, 0); // 监听可写事件}else if (conn_poll[fd].status == 2){SetEvent(fd, EPOLLOUT, 0); // 监听可写事件}else if (conn_poll[fd].status == 0){SetEvent(fd, EPOLLIN, 0); // 监听可读事件}return count;
}
2、视频流
可惜视频流失败,大体思路也是分段,但不可和文本、图片的资源一样看待,后续有时间再研究。
三、总结
1、C/C++可以实现HTTP请求,但相对于专门处理web的java,c#,php等语言,显得笨拙。
2、如果要实现高性能的服务器,C/C++是首选。
3、对于频繁接收部分数据,发送部分数据的场景,分段处理是个不错的选择;状态机应该优先考虑。
4、状态机使得代码逻辑更加清晰,便于扩展,更容易处理错误。
5、循环不易于错误处理,且代码会变得更加复杂和难以理解。
Code:
代码链接
相关文章:

网络学习-利用reactor实现http请求(六)
一、实现HTTP请求 1、印象里面,总有人说C/C语言不能实现HTTP请求,其实不然。C/C语言完全可以实现HTTP请求。通过对select,poll,epoll等IO多路复用技术的学习以及reactor模式的学习,完全能够实现HTTP请求。 2、webserver 主要解决两个问题 …...
云原生安全:IaaS安全全解析(从基础到实践)
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念:IaaS的核心价值与安全边界 1.1 什么是IaaS? 基础设施即服务(Infrastructure as a Service)是云计算的基础层,提供虚拟机、存储、网络等基础资源。用户通过…...

【IC_Design】跨时钟域的寄存器更新后锁存
目录 设计逻辑框图场景概述总结电路使用注意事项***波形图代码 设计逻辑框图 场景概述 最典型的应用场景就是——在一个时钟域(比如 CPU/总线域)更新了一个多位配置字,需要把它安全地送到另一个时钟域(比如时钟发生器、串口、视频…...
Spring AI 之提示词
提示词(Prompts)是引导人工智能(AI)模型生成特定输出的输入内容。这些提示词的设计和措辞会显著影响模型的响应。 在 Spring AI 中,与 AI 模型进行交互的最低层级上,处理提示词的方式与 Spring MVC 中管理“视图”(View)有些相似。这涉及创建包含动态内容占位符的冗长…...
亚远景-汽车软件开发的“升级之路”:ASPICE各等级说明
ASPICE(Automotive SPICE)将汽车软件开发过程的成熟度划分为六个等级,从0级到5级,每个等级代表了组织在软件开发过程中的不同能力水平。以下是各等级的详细说明: 等级0:不完整(Incomplete&#…...

Java微服务架构:Spring Cloud全栈指南,附最新Demo源码,可独立运行!
在日常java开发中你是不是经常遇到这种问题:开发中不知道要引入什么版本,创建新项目时直接从老工程拷贝引入了一堆杂乱的包,随便升级下其中一个包就导致整个微服务跑不起来! 如果你也遇到这种问题,可以认证看下本篇文…...

使用LLaMA-Factory微调ollama中的大模型(一)------家用电脑安装LLaMA-Factory工具
前提:本机已安装python,且版本大于3.9,推荐3.10 官方规定如下 我已安装 1.安装torch 查看自己电脑显卡信息 说明我没有装CUDA 使用 nvidia-smi 命令查看驱动信息 说明我NVIDIA 显卡已安装驱动,支持的 CUDA Runtime 版本为 12.6…...
支持向量机(SVM):分类与回归的数学之美
在机器学习的世界里,支持向量机(Support Vector Machine,简称 SVM)是一种极具魅力且应用广泛的算法。它不仅能有效解决分类问题,在回归任务中也有着出色的表现。下面,就让我们深入探索 SVM 如何在分类和回归…...
手撕I2C和SPI协议实现
手撕I2C和SPI协议实现 目录 I2C协议原理I2C位操作实现I2C驱动代码编写SPI协议原理SPI位操作实现SPI驱动代码编写 I2C协议原理 I2C(Inter-Integrated Circuit)是一种串行通信总线,使用两根线:SCL(时钟线)…...

人工智能+:职业价值的重构与技能升级
当“人工智能”成为产业升级的标配时,一个令人振奋的就业图景正在展开——不是简单的岗位替代,而是职业价值的重新定义。这场变革的核心在于,AI并非抢走工作机会,而是创造了人类与技术协作的全新工作范式。理解这一范式转换的逻辑…...

JVM部分内容
1.JVM内存区域划分 为什么要划分内存区域,JAVA虚拟机是仿照真实的操作系统进行设计的,JVM也就仿照了它的情况,进行了区域划分的设计。 JAVA进程也就是JAVA虚拟机会从操作系统申请内存空间给进程使用,JVM内存空间划分,…...
paddlehub搭建ocr服务
搭建环境: Ubuntu20.041080Ti显卡 由于GPU硬件比较老,是Pascal架构,只能支持到paddle2.4.2版本,更高版本无法支持;同时,因为paddle老版本的依赖发生了变化,有些地方存在冲突,花费了…...

python-leetcode 68.有效的括号
题目: 给定一个只包括“(”),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足:左括号必须用相同类型的右括号闭合;左括号必须以正确的顺序闭合,…...
人性的裂痕:社会工程学如何成为网络安全的隐形战场
引言 在技术高度发达的今天,网络安全防护墙看似坚不可摧,但黑客却总能找到一条“捷径”——利用人性的弱点。这种被称为“社会工程学”的攻击手段,不依赖复杂的代码漏洞,而是通过心理操纵和信息欺骗,让受害者主动交出…...
ObservableCollection序列化,和监听链表内元素变化
1.ObservableCollection序列化 情景:定义了A类、B类; A类里面有ObservableCollection<B>类型的属性,假设这个属性名称为BList; ObservableCollection<MotionIntervalSegmentation> motionIntervalSegmentation; [B…...

NLP学习路线图(四):Python编程语言
引言 自然语言处理(Natural Language Processing, NLP)是人工智能领域最引人注目的分支之一。从智能客服到机器翻译,从舆情分析到聊天机器人,NLP技术正在重塑人机交互的边界。本文将结合Python编程语言,带您走进NLP的…...
matlab实现无线通信组
无线通信组网涉及多个节点之间的通信,通常需要考虑节点的布局、信号传输、路径损耗、干扰等问题。在MATLAB中,可以通过模拟节点的位置、信号强度、路径损耗等因素来实现一个简单的无线通信组网程序。 1. 节点布局 首先,我们需要定义网络中的…...
基于单片机的室内采光及可燃气体泄漏报警装置设计
标题:基于单片机的室内采光及可燃气体泄漏报警装置设计 内容:1.摘要 随着人们对室内环境安全和舒适度要求的提高,设计一种能实时监测室内采光和可燃气体泄漏情况并及时报警的装置具有重要意义。本设计基于单片机实现室内采光及可燃气体泄漏报警功能,采用…...

Serverless爬虫架构揭秘:动态IP、冷启动与成本优化
一、问题背景:旧技术的瓶颈 在传统爬虫架构中,我们通常部署任务在本地机器或虚拟机中,搭配定时器调度任务。虽然这种方式简单,但存在以下明显缺陷: 固定IP易被封禁:目标网站如拼多多会通过IP频率监控限制…...

从单体到分布式:深入解析Data Mesh架构及其应用场景与价值
Data Mesh(数据网格)是一种新兴的数据架构范式,旨在解决传统集中式数据平台的可扩展性、敏捷性和治理问题。它强调领域驱动的分布式数据所有权、自助数据平台以及跨组织的协作,使数据成为产品,并通过去中心化的方式提高…...

AI大模型ms-swift框架实战指南(十三):Agent智能体能力构建指南
系列篇章💥 No.文章1AI大模型ms-swift框架实战指南(一):框架基础篇之全景概览2AI大模型ms-swift框架实战指南(二):开发入门之环境准备3AI大模型ms-swift框架实战指南(三)…...

LLM最后怎么输出值 解码语言模型:从权重到概率的奥秘
LM Head Weights(语言模型头部权重):左侧的“LM Head Weights”表示语言模型头部的权重矩阵,它是模型参数的一部分。权重矩阵与输入数据进行运算。Logits(未归一化对数概率):经过与LM Head Weig…...

Leetcode百题斩-回溯
回溯是一个特别经典的问题,也被排在了百题斩的第一部分,那么我们接下来来过一下这个系列。 这个系列一共八道题,偶然间发现我两年前还刷到这个系列的题,回忆起来当时刚经历淘系大变动与jf出走海外事件,大量同事离职闹…...

超小多模态视觉语言模型MiniMind-V 训练
简述 MiniMind-V 是一个超适合初学者的项目,让你用普通电脑就能训一个能看图说话的 AI。训练过程就像教小孩:先准备好图文材料(数据集),教它基础知识(预训练),再教具体技能…...

边缘云的定义、实现与典型应用场景!与传统云计算的区别!
一、什么是边缘云? 边缘云是一种分布式云计算架构,将计算、存储和网络资源部署在靠近数据源或终端用户的网络边缘侧(如基站、本地数据中心或终端设备附近),而非传统的集中式云端数据中心。 核心特征&…...
HarmonyOS 鸿蒙应用开发基础:父组件和子组件的通信方法总结
在鸿蒙开发中,ArkUI声明式UI框架提供了一种现代化、直观的方式来构建用户界面。然而,由于其声明式的特性,父组件与子组件之间的通信方式与传统的命令式框架有所不同。本文旨在详细探讨在ArkUI框架中,父组件和子组件通信的方法总结…...
小白的进阶之路系列之三----人工智能从初步到精通pytorch计算机视觉详解下
我们将继续计算机视觉内容的讲解。 我们已经知道了计算机视觉,用在什么地方,如何用Pytorch来处理数据,设定一些基础的设置以及模型。下面,我们将要解释剩下的部分,包括以下内容: 主题内容Model 1 :加入非线性实验是机器学习的很大一部分,让我们尝试通过添加非线性层来…...

Scrapy爬取heima论坛所有页面内容并保存到MySQL数据库中
前期准备: Scrapy入门_win10安装scrapy-CSDN博客 新建 Scrapy项目 scrapy startproject mySpider # 项目名为mySpider 进入到spiders目录 cd mySpider/mySpider/spiders 创建爬虫 scrapy genspider heima bbs.itheima.com # 爬虫名为heima ,爬…...
HarmonyOS NEXT~鸿蒙系统下的Cordova框架应用开发指南
HarmonyOS NEXT~鸿蒙系统下的Cordova框架应用开发指南 1. 简介 Apache Cordova是一个流行的开源移动应用开发框架,它允许开发者使用HTML5、CSS3和JavaScript构建跨平台移动应用。随着华为鸿蒙操作系统(HarmonyOS)的崛起,将Cordova应用适配到…...

com.alibaba.fastjson2 和com.alibaba.fastjson 区别
1,背景 最近发生了一件很奇怪的事:我们的服务向第三方发送请求参数时,第三方接收到的字段是首字母大写的 AppDtoList,但我们需要的是小写的 appDtoList。这套代码是从其他项目A原封不动复制过来的,我们仔细核对了项目…...