网络学习-利用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:
代码链接

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

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

相关文章

【VSCode】修改侧边文件资源管理器中的文件夹折叠模式

默认为紧凑模式&#xff1a; 然后我们勾选该项为宽松模式&#xff1a;

信息化时代国产主板如何防止信息泄露?

在数字化时代&#xff0c;每一份机密的泄露都可能成为我们的致命伤&#xff0c;尤其是如今网络如此发达的5G时代&#xff0c;如何防止网络信息泄密&#xff0c;已经成为每个人必须直面的问题。随着网络安全问题日益严重&#xff0c;企业和个人对网络安全的重视程度不断加深&…

vue的简单使用

1.vue的引入 引入函数&#xff0c;创建createApp对象 <div id"app">{{ message }}</div><script type"module">import { createApp, ref } from https://unpkg.com/vue3/dist/vue.esm-browser.jscreateApp({setup() {const message re…

【图像生成大模型】HunyuanVideo:大规模视频生成模型的系统性框架

HunyuanVideo&#xff1a;大规模视频生成模型的系统性框架 引言HunyuanVideo 项目概述核心技术1. 统一的图像和视频生成架构2. 多模态大语言模型&#xff08;MLLM&#xff09;文本编码器3. 3D VAE4. 提示重写&#xff08;Prompt Rewrite&#xff09; 项目运行方式与执行步骤1. …

DPDK 技术详解:榨干网络性能的“瑞士军刀”

你是否曾感觉&#xff0c;即使拥有顶级的服务器和万兆网卡&#xff0c;你的网络应用也总是“喂不饱”硬件&#xff0c;性能总差那么一口气&#xff1f;传统的网络处理方式&#xff0c;就像在高速公路上设置了太多的收费站和检查点&#xff0c;限制了数据包的“奔跑”速度。 今…

力扣网-复写零

1.题目要求 2.题目链接 1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 3.题目解答 class Solution {public void duplicateZeros(int[] arr) {int cur0,dest-1,narr.length;while(cur<n){//遇到0就dest走两步if(arr[cur]0){dest2;}//遇到非零元素dest就走一步els…

STL中的Vector(顺序表)

vector容器的基本用法&#xff1a; template<class T> class vector { T* _a; size_t size; size_t capacity; } 尾插和遍历&#xff1a; vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3);//遍历 for(int i0;i<v.size();i) {cout<<…

Hass-Panel - 开源智能家居控制面板

文章目录 ▎项目介绍&#xff1a;预览图▎主要特性安装部署Docker方式 正式版Home Assistant Addon方式详细安装方式1. Home Assistant 插件安装&#xff08;推荐&#xff09;2. Docker 安装命令功能说明 &#xff1a;3. Docker Compose 安装升级说明Docker Compose 版本升级 功…

ctfhub技能书http协议

http://challenge-ffe8afcf1a75b867.sandbox.ctfhub.com:10800/index.php curl -v -X CTFHUB http://challenge-ffe8afcf1a75b867.sandbox.ctfhub.com:10800/index.php curl&#xff1a;用于发送 HTTP 请求的命令行工具。 -v&#xff08;--verbose&#xff09;&#xff1a;开启…

Eigen与OpenCV矩阵操作全面对比:最大值、最小值、平均值

功能对比总表 功能Eigen 方法OpenCV 方法主要区别最大值mat.maxCoeff(&row, &col)cv::minMaxLoc(mat, NULL, &maxVal, NULL, &maxLoc)Eigen需要分开调用&#xff0c;OpenCV一次获取最小值mat.minCoeff(&row, &col)cv::minMaxLoc(mat, &minVal, NU…

结课作业01. 用户空间 MPU6050 体感鼠标驱动程序

目录 一. qt界面实现 二. 虚拟设备模拟模拟鼠标实现体感鼠标 2.1 函数声明 2.2 虚拟鼠标实现 2.2.1 虚拟鼠标创建函数 2.2.2 鼠标移动函数 2.2.3 鼠标点击函数 2.3 mpu6050相关函数实现 2.3.1 i2c设备初始化 2.3.2 mpu6050寄存器写入 2.3.3 mpu6050寄存器读取 2.3.…

[Docker排查] 镜像拉取/容器启动/网络不通?Docker常见错误与解决方案

Docker&#xff0c;这个让无数开发者和运维工程师高呼“真香”的容器化技术&#xff0c;凭借其轻量、快速、可移植的特性&#xff0c;极大地简化了应用的开发、测试和部署流程。但即便是再“香”的技术&#xff0c;也难免有“闹脾气”的时候。你是不是也遇到过这样的“抓狂瞬间…

Oracle如何解决LATCH:CACHE BUFFERS CHAINS

CACHE BUFFERS CHAINS LATCH主要用于保护HASH CHAIN结构。一个CACHE BUFFERS CHAINS LATCH保护着多条HASH CHAIN。可以通过查看隐含参数_db_block_hash_latches的值或者查询vlatch_children视图获得系统中CACHE BUFFER CHAIN LATCH的数量。目前系统中CACHE BUFFER CHAIN LATCH的…

手搓四人麻将程序

一、麻将牌的表示 在麻将游戏中&#xff0c;总共有一百四十四张牌&#xff0c;这些牌被分为多个类别&#xff0c;每个类别又包含了不同的牌型。具体来说&#xff0c;麻将牌主要包括序数牌、字牌和花牌三大类。序数牌中&#xff0c;包含有万子、条子和筒子&#xff0c;每种花色…

spring cloud config更新配置

在开发微服务时&#xff0c;往往需要有开发环境、测试环境和生产环境&#xff0c;手动修改配置环境是一件很麻烦的事情&#xff0c;因此&#xff0c;这里使用spring cloud config管理配置环境。要使用spring cloud config&#xff0c;需要先在GitHub搭建一个仓库。 一、仓库搭…

MySQL 5.7 实战:JSON 字段提取、Base64 解码与引号问题全解析

一、背景与问题场景 在 MySQL 数据库中&#xff0c;存储 JSON 格式数据&#xff08;如用户行为日志、配置参数、扩展信息&#xff09;的场景日益普遍。当需要从 JSON 字段中提取特定键值&#xff08;如info&#xff09;并进行 Base64 解码时&#xff0c;常遇到以下问题&#x…

自研Rise系列之BI简单易用的大屏系统

BI系统是制作可视化大屏报表的常用工具之一&#xff0c;因其具备实时更新、综合分析多来源数据、直观展现分析结果、支持多维自助分析等特点而广受欢迎。在BI系统上设计制作可视化大屏后&#xff0c;只需接入大屏硬件即可&#xff0c;因此BI系统的选择就成了重中之重。 在可视化…

飞桨paddle import fluid报错【已解决】

跟着飞桨的安装指南安装了paddle之后 pip install paddlepaddle有一个验证&#xff1a; import paddle.fluid as fluid fluid.install check.run check()报错情况如下&#xff0c;但是我在pip list中&#xff0c;确实看到了paddle安装上了 我import paddle别的包&#xff0c…

第18天-NumPy + Pandas + Matplotlib多维度直方图

示例1:带样式的柱状图 python 复制 下载 import numpy as np import pandas as pd import matplotlib.pyplot as plt# 生成数据 df = pd.DataFrame(np.random.randint(10, 100, size=(8, 4)),columns=[Spring, Summer, Autumn, Winter],index=[2015, 2016, 2017, 2018, 20…

关于 Web 安全实践:4. 文件上传功能的风险分析与防护

定义&#xff1a;文件上传风险点是指应用程序允许用户上传文件&#xff0c;但没有严格校验上传文件的类型、内容、路径等属性&#xff0c;导致攻击者可以上传并执行恶意代码。 绕过方式&#xff1a; 前端绕过 1. 前端限制的原理 前端限制上传文件类型的常见方式有三种&#…