ESP32基础应用之HTTP 服务器

2023-11-03


参考资料:

  1. esp32 http服务器编程指南

1 HTTP服务器简介

  1. HTTP服务器一般指Web服务器,是指驻留于因特网上某种类型计算机的程序,可以处理浏览器等Web客户端的请求并返回相应响应,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache、 Nginx 、IIS。
  2. Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件反馈到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。

参考来源:百度百科 HTTP服务器

2 ApiPost测试工具

使用ApiPost作为测试工具,如图:
在这里插入图片描述
链接:

  1. ApiPost官方地址
  2. ApiPost使用说明

3 HTTP服务器实验

参考例程:Simple HTTPD Server Example

注意:ESP32开发板作为HTTP服务器;ApiPost作为客户端
实验流程大概为:

  1. httpd_start() :创建 HTTP 服务器的实例,根据具体的配置为其分配内存和资源,并返回该服务器实例的句柄。服务器使用了两个套接字,一个用来监听 HTTP 流量(TCP 类型),另一个用来处理控制信号(UDP 类型),它们在服务器的任务循环中轮流使用。通过向 httpd_start() 传递 httpd_config_t 结构体,可以在创建服务器实例时配置任务的优先级和堆栈的大小。TCP 流量被解析为 HTTP 请求,根据请求的 URI 来调用用户注册的处理程序,在处理程序中需要发送回 HTTP 响应数据包。
  2. httpd_register_uri_handler():通过传入 httpd_uri_t 结构体类型的对象来注册 URI 处理程序。该结构体包含如下成员:uri 名字,method 类型(比如 HTTPD_GET/HTTPD_POST/HTTPD_PUT 等等), esp_err_t *handler (httpd_req_t *req) 类型的函数指针,指向用户上下文数据的 user_ctx 指针。
  3. httpd_stop():根据传入的句柄停止服务器,并释放相关联的内存和资源。这是一个阻塞函数,首先给服务器任务发送停止信号,然后等待其终止。期间服务器任务会关闭所有已打开的连接,删除已注册的 URI 处理程序,并将所有会话的上下文数据重置为空。

3.1 ApiPost之GET测试

查看get注册参数以及处理函数代码(详细代码请参考例程)。

static const httpd_uri_t hello = {
    .uri       = "/hello",            //具体路径,如  http://192.168.3.173:80/hello  
    .method    = HTTP_GET,            //方法method 
    .handler   = hello_get_handler,   //处理函数
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = "Hello World!i am esp32 2021.06.25"  //给客户端的响应
};
/* An HTTP GET handler */
static esp_err_t hello_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;

    //获取请求头,并打印出来
    /* Get header value string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        /* Copy null terminated value string into buffer */
        if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Host: %s", buf);
        }
        free(buf);
    }
    buf_len = httpd_req_get_hdr_value_len(req, "Accept-Language") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "Accept-Language", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Accept-Language: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "User-Agent") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "User-Agent", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => User-Agent: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "Connection") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "Connection", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Connection: %s", buf);
        }
        free(buf);
    }
	
    buf_len = httpd_req_get_hdr_value_len(req, "content-type") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "content-type", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => content-type: %s", buf);
        }
        free(buf);
    }

    //获取query并打印出来,再分类
    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found URL query => %s", buf);
            char param[32];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
            }
            if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param);
            }
            if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
            }
        }
        free(buf);
    }

    //设置响应头
    /* Set some custom headers */
    httpd_resp_set_hdr(req, "Custom-Header-11", "Custom-Value-1");
    httpd_resp_set_hdr(req, "Custom-Header-22", "Custom-Value-2");

    /* Send response with custom headers and body set as the
     * string passed in user context*/
    const char* resp_str = (const char*) req->user_ctx;
    httpd_resp_send(req, resp_str, strlen(resp_str));

    /* After sending the HTTP response the old HTTP request
     * headers are lost. Check if HTTP request headers can be read now. */
    if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
        ESP_LOGI(TAG, "Request headers lost");
    }
    return ESP_OK;
}

关于HTTP报文接收请参考:这里

  1. 编译并烧录程序,打开串口,记录IP地址在这里插入图片描述
  2. 打开ApiPost,发送get的uri。在这里插入图片描述
  3. 打开ESP32开发板的串口,得到数据如下 :在这里插入图片描述
  4. 打开ApiPost查看响应数据在这里插入图片描述在这里插入图片描述在这里插入图片描述
    请求头解释如下:
    Accept-Encoding: gzip, deflate, br
    表示浏览器支持的编码是gzip、deflate、br(客户端支持的编码)
    Accept-Language: zh-CN
    浏览器支持的语言分别是简体中文和中文(当前客户端可以支持的语言)
    User-Agent:ApiPOST Runtime +https://www.apipost.cn
    用户代理,客户端是ApiPOST,如果是其他浏览器则显示其他浏览器
    更多请求头解释清参考:HTTP服务器(一)

3.2 ApiPost之POST测试


static const httpd_uri_t echo = {
    .uri       = "/echo",            //具体路径,如  http://192.168.3.173:80/echo
    .method    = HTTP_POST,          //方法method 
    .handler   = echo_post_handler,  //处理函数
    .user_ctx  = NULL
};

/* An HTTP POST handler */
static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[100];
    int ret, remaining = req->content_len;

    while (remaining > 0) {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf,
                        MIN(remaining, sizeof(buf)))) <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                /* Retry receiving if timeout occurred */
                continue;
            }
            return ESP_FAIL;
        }

        /* Send back the same data */
        httpd_resp_send_chunk(req, buf, ret);  
        remaining -= ret;

        /* Log data received */
        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", ret, buf);
        ESP_LOGI(TAG, "====================================");
    }

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

  1. 打开ApiPost,发送POST的uri。在这里插入图片描述
  2. 打开ESP32开发板的串口,得到数据如下 :在这里插入图片描述

3.3 ApiPost值PUT测试

/* An HTTP PUT handler. This demonstrates realtime
 * registration and deregistration of URI handlers
 */
static esp_err_t ctrl_put_handler(httpd_req_t *req)
{
    char buf;
    int ret;

    if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) {
        if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
            httpd_resp_send_408(req);
        }
        return ESP_FAIL;
    }

    if (buf == '0') {
        /* URI handlers can be unregistered using the uri string */
        ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
        httpd_unregister_uri(req->handle, "/hello");
        httpd_unregister_uri(req->handle, "/echo");
        /* Register the custom error handler */
        httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler);
    }
    else {
        ESP_LOGI(TAG, "Registering /hello and /echo URIs");
        httpd_register_uri_handler(req->handle, &hello);
        httpd_register_uri_handler(req->handle, &echo);
        /* Unregister custom error handler */
        httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL);
    }

    /* Respond with empty body */
    httpd_resp_send(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t ctrl = {
    .uri       = "/ctrl",
    .method    = HTTP_PUT,
    .handler   = ctrl_put_handler,
    .user_ctx  = NULL
};
  1. 打开ApiPost,发送PUT的uri,且Body部分写0在这里插入图片描述
  2. 打开ESP32开发板的串口,得到数据如下 :在这里插入图片描述
  3. 打开ApiPost,发送PUT的uri,且Body部分写除0其他数据在这里插入图片描述
  4. 打开ESP32开发板的串口,得到数据如下 :在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ESP32基础应用之HTTP 服务器 的相关文章

  • 边缘计算浅析

    最近 新基建 是个热词 那么新基建到底是什么 与之紧密相关的5G何去何从 这给边缘计算带来了什么机遇 边缘计算的生态产业链条是怎样的 它的典型特征和经济效益是什么 本文将为大家带来分享 新基建是什么 近日 国家发改委官方首次明确了 新基建
  • 5G 的三大应用场景——ITU-R原文

    每次写 5G 的材料时都会提及 5G 的三大应用场景 虽然这是一个众人皆知的常识 但是如果不引用一下的话有些不严谨 苦于一直没找到 ITU 的原文 之前引用的都是移动通信教材那本书 今天狠下心来花时间找了原文 功夫不负有心人 可算给我找到了
  • 找出数组中第 k 小的数

    题目 给定整型数组 S 和整数 k S的长度为n 1 lt k lt n 请输出数组中第 k 小的数 输入的第一行为数组 S 的各个元素 输入的第二行为整数 k 测试案例 1 输入 3 1 2 5 4 6 3 输出 3 我相信大家的第一想法
  • 工程师如何对待开源

    工程师如何对待开源 本文是笔者作为一个在知名科技企业内从事开源相关工作超过 20 年的工程师 亲身经历或者亲眼目睹很多工程师对待开源软件的优秀实践 也看到了很多 Bad Cases 所以想把自己的一些心得体会写在这里 供工程师进行参考 希望
  • mongodb学习笔记–C++操作mongodb

    mongodb学习笔记 C 操作mongodb 在学习mongodb过程当中 必须学习的就是用C Java PHP C 等 操作mongodb 这里讲述C 操作mongodb 在官方提供的mongo cxx driver驱动中有相关的操作例
  • Golang手动安装包

    在写代码过程中经常需要import github com 官方推荐的为go get github com 下载后可以直接自动安装 但是国内由于墙的原因导致下载失败 在此介绍如何在Linux环境下手动安装go包 以 github com ma
  • [网络工程师]-网络规划与设计-需求分析

    1 建网目标分析 建网目标的分析内容包括最终目标分析和近期目标分析 1 1最终目标分析 最终目标分析内容包括 网络建设到怎样的规模 如何满足用户需求 采用的是否是TCP IP 体系结构是Intranet还是非Intranet 即是否为企业网
  • Oracle19c ORA-00904: “WMSYS“.“WM_CONCAT“: 标识符无效

    错误描述 oracle19c ORA 24344 成功 但出现编译错误 ORA 00904 WMSYS WM CONCAT 标识符无效 解决办法 设置实例 export ORACLE SID test1 首先使用dba账号登录oracle数
  • Java06-MyBatis如何实现多表查询(一对一、一对多)

    前提 总结这个文章的前提是要会基本的SQL语句 我用的MySQL 和JDBC的基本实现 在这个基础上 我们可以通过一些标签或者注解去实现对数据库的多表联查基于一对一和一对多的关系 第二点 我们在制作数据库时一定要考虑不同的表之间的关系 这种
  • openstack装配置 Neutron( 控制节点

    在控制节点 controller 安装 Neutron 服务 同时配置支持 vxlan 1 登录数据库创建 neutron 数据库 MariaDB none gt CREATE DATABASE neutron default charac
  • 【大数据】美团 DB 数据同步到数据仓库的架构与实践

    美团 DB 数据同步到数据仓库的架构与实践 1 背景 2 整体架构 3 Binlog 实时采集 4 离线还原 MySQL 数据 5 Kafka2Hive 6 对 Camus 的二次开发 7 Checkdone 的检测逻辑 8 Merge 9
  • linux下应用开发之按键信号结束线程

    linux应用层经常使用线程 在线程中while循环等待 或者应用中也会有while 那么如果自己写demo或者使用命令行运行 经常用到使用Ctrl C键结束应用 比如main函数中加入signal信号处理 Stop就是信号处理回调函数 主
  • FSA-Net 模型运行——代码调试

    文章目录 一 代码连接 一 代码调试 一 环境配置 二 运行环境 二 参数设置 一 模型训练 二 模型测试 三 demo运行 三 报错汇总 一 代码连接 提示 跑了三天终于把代码跑通了 谢谢各路神仙菩萨 可以先看主要参考博客里大神的博客 讲
  • D3dcompiler_43.dll缺失怎么修复?快速修复方法分享

    D3dcompiler 43 dll缺失怎么修复 在使用Windows系统的过程中 您可能会遇到 D3dcompiler 43 dll缺失 的问题 这个问题通常会导致应用程序无法正常运行 因为它是Direct3D编译器的一部分 而Direc
  • 2020-08-13

    AlertDialog You need to use a Theme AppCompat theme or descendant with this activity 解决方案 将 super context 修改为 super cont
  • kingsoft的服务器信息,Win10系统kingsoft是什么文件夹?可以删除吗?

    在使用Win10系统的过程中 有很多人在盘符里面发现了一个kingsoft文件夹 于是就想问Win10系统kingsoft是什么文件夹 可以删除吗 其实这个问题很简单 但是如果你不知道的话 那就赶紧看看小编整理的以下文章内容吧 Win10系
  • shell脚本实战-while循环语句

    前言 上文我们讨论了for循环的使用 在有限循环里 我们使用for循环是很方便的一件事情 今天我们来探讨下while循环 while循环语句的语法分析 语法格式一 while 条件 do 操作 done 语法格式二 while read l
  • 生成随机小数的函数python_哪个选项是random库中用于生成随机小数的函数?

    其它 一个整数 它加上100后是一个完全平方数 再加上168又是一个完全平方数 试编写代码输出该整数 要求 1 粘贴代码图片 图片需包括行号 代码不可超过6行 争取4行 2 粘贴结果图片 符合条件的整数有四个 单选题 哪个选项不能正确引用t

随机推荐

  • PD16 for Mac(支持M1芯片)v16.3.2(50531)中文版介绍

    PD16虚拟机中文版是mac上最强大也是最好用的虚拟机软件 Parallels Desktop Mac 16 可以显着降低磁盘 内存和CPU使用率 而且针对Windows 10更新进行了优化 更新了超过50个新功能 可以让您更充分地利用你的
  • Out-Of-Vocabulary(OOV)的理解

    OOV 问题是NLP中常见的一个问题 其全称是Out Of Vocabulary 下面简要的说了一下OOV 怎么解决 下面说一下Bert中是怎么解决OOV问题 如果一个单词不在词表中 则按照subword的方式逐个拆分token 如果连逐个
  • 汉字简/繁体转换

  • C语言:删除字符

    本题要求实现一个删除字符串中的指定字符的简单函数 函数接口定义 void delchar char str char c 其中char str是传入的字符串 c是待删除的字符 函数delchar的功能是将字符串str中出现的所有c字符删除
  • 【kernel envirment】config tiny X86 kernel with vfs

    Automatically generated file DO NOT EDIT Linux x86 4 19 0 Kernel Configuration Compiler gcc Ubuntu 7 3 0 27ubuntu1 18 04
  • cocos creator 血条跟随3d convertToUINode导致的问题,使用worldToScreen解决跟随偏离问题

    cocos creator3 3 2 实现血条跟随 一开始使用的camera的converToUINode 也是按照麒麟子大师的博客操作 结果最终的效果 在屏幕中间 血条显示正常 在屏幕边缘就开始出现偏差 x和y都有的偏差 最终也没有解决方
  • 择后自动上传html代码,GitLab + Jenkins + Webhook 实现Push代码后自动更新

    一 介绍 通常是开发后的代码先推到Gitlab上管理 然后在Jenkins里通过脚本构建代码发布 这种方式每次在发版的时候 需要人工去执行jenkins上的构建动作 有时显得过于繁琐 Gitlab的Webhook功能 通过Webhook的相
  • 九月份参加OPPO和腾讯Android面试:技术一面+二面+三面+HR四面,我的面经总结!

    之前很多时候我是拒绝说我的面试经验的 因为我们简历经历不一样问的问题也会不一样 且大厂面试光靠背几个面试题就想过还是比较难的 因此在这里提醒一下大家不要临时抱佛脚 你花几天能背下的东西 别人花几天一定能超过你的 但我们花几年沉淀的东西 人家
  • 公司企业微信小程序创建步骤

    随着新一代互联网的发展 小程序已经成为当今社会不可或缺的重要部分 它的简单易用 公司企业小程序是一种基于微信平台构建的应用程序 旨在为企业提供灵活便捷的营销服务 关于公司企业微信小程序创建步骤 可分为以下几个部分 一 申请微信公众号并创建小
  • 2022年,软件测试还能学吗?别学了,软件测试岗位饱和了...

    8年前 我懵懂的选择了软件测试这个行业 穷困潦倒的时候 爸妈给我付了2万块钱进入了一家培训机构 我怀着感激和破釜沉舟的情绪开始学习软件测试 3个月的学习时间 住群租宿舍 吃盒饭 平时上课认真听讲 周末就跑自习室 在学了基础课程之后 找工作的
  • vue中纯JS调用自定义组件

    案例以vant为例 1 首先创建index vue index js文件 2 index vue跟我们平常写的组件是一样的
  • 51单片机学习笔记(十二) - 红外遥控

    文章目录 前言 一 红外遥控的背景知识 1 人机交互 2 红外遥控的相关知识 二 原理图电路分析 三 NEC协议讲解 1 逻辑1与逻辑0的表示 2 NEC协议格式 3 NEC协议的关键点 四 代码实现 总结 前言 随着科技的发展 红外遥控器
  • 【Spring Boot整合MyBatis教程】

    Spring Boot是由Pivotal团队提供的全新框架 其设计目的是用来简化新Spring应用的初始搭建以及开发过程 该框架使用了特定的方式来进行配置 从而使开发人员不再需要定义样板化的配置 通过这种方式 Spring Boot致力于在
  • 用4种语言编写端口扫描器(Java、C、Python、Go)

    Java import java net InetSocketAddress import java net Socket import java util concurrent ExecutorService import java ut
  • Ghost-Docker(五)Nginx+SSL+Https

    使用 Ngins SSL 证书 为 Ghost 实现 Https 访问 HTTPS 协议是由 HTTP 加上 TLS SSL 协议构建的可进行加密传输 身份认证的网络协议 主要通过数字证书 加密算法 非对称密钥等技术完成互联网数据传输加密
  • ElementUI过渡动画篇

    ElementUI过渡动画篇 element官方提供的过渡动画并不能很好的满足使用 我尝试过几种过渡动画的设置方式 最终选择了Animate css 一 使用方法 引入 引入 npm install animate css save 然后在
  • 保姆级连载讲义学Python:第四篇多文件项目的演练

    多文件项目的演练 开发 项目 就是开发一个 专门解决一个复杂业务功能的软件 通常每 一个项目 就具有一个 独立专属的目录 用于保存 所有和项目相关的文件 一个项目通常会包含 很多源文件 目标 在项目中添加多个文件 并且设置文件的执行 多文件
  • FastAPI从入门到实战(10)——响应模型与状态码

    前面一直记录的是请求相关的内容 这篇文章开始记录一下响应相关的内容 包括请求模型和模型继承以及状态码等相关的内容 一个任意dict构成的基本响应 任意dict构成的响应 app06 get stu06 dict response model
  • STL容器使用中的拷贝成本

    include stdafx h include
  • ESP32基础应用之HTTP 服务器

    文章目录 1 HTTP服务器简介 2 ApiPost测试工具 3 HTTP服务器实验 3 1 ApiPost之GET测试 3 2 ApiPost之POST测试 3 3 ApiPost值PUT测试 参考资料 esp32 http服务器编程指南