IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Arduino 如何联网发送图片? -> 正文阅读

[网络协议]Arduino 如何联网发送图片?

简介

本文是在 ESP32-CAN 中实现的,其他单片机实现方法一致,主要涉及 HTTP 发送文件。本章所采用的请求为 POST 请求 。GET 请求会更容易 。

分别讲解

HTTP请求报文头

?HTTP 请求报文格式如图:请求方法为 POST 或者 GET 。URL 为 请求地址,可以为 / 。协议版本 HTTP/1.1即可。 回车符 \r 换行符\n
有几个必不可少的头部字段:

  • Host 服务器的域名/IP地址和端口号
  • Content-Type 内容类型
  • Content-Length 内容大小
    HTTP请求头报文

HTTP 请求报文体

我们要发送文件,所以报文体当然就是文件了,当然,文件也有专门用来发送的格式
其中一种格式为:

–【随机码】【\r\n】
Content-Disposition: form-data; name=【数据标识】; filename=“【文件名】”【\r\n】
Content-Type: 【文件类型】【\r\n】
【文件二进制编码流】
–【随机码】–

文件类型如果是JPG的话就是image/jpeg

整合报文

Content-Type

随机码要在请求头 Content-Type 告诉服务器随机码是什么

Content-Type: multipart/form-data; boundary=【随机码】

Content-Length

Arduino 的 String 太长会出现BUG,所以我们还是用手动计算的方式来获取请求体的大小,而不是全部整合到一个字符串中再求字符串长度。

// 二进制流前面的报文
String fileHead = "--" + randomCode  + "\r\n" +
                           "Content-Disposition: form-data; name=\"img\"; filename=\"" + randomCode + ".jpg\"" + "\r\n" +
                           "Content-Type: image/jpeg"  + "\r\n";
// 获取文件大小
size_t jpgsize = 0 ;
for( jpgsize = 0 ; ;jpgsize++ ){
	if( fb->buf[jpgsize] == 0xff ){
		if( fb->buf[jpgsize+1] ==0xd9 ){
			jpgsize += 2 ;
			break;
		}
	}
}
// 太大了就转 long 或者直接转String 
unsigned int  bodySize = ( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2  ); 

Content-Length: 【bodySize请求体大小】

按顺序发送

做完这几步以后,就可以把我们的报文按顺序发送出去了,下面有一个 ESP32-CAN 发送一张图片并获取响应的例子。

ESP32-CAN实现图片上传代码段

void send_camera_img(){
    // acquire a frame
    WiFiClient client;
    camera_fb_t *fb = esp_camera_fb_get();
	
	// 域名 请求地址
	string domain =  "" ;

    if ( client.connect(domain,80)){ 
        Serial.println(" Success!");        // 连接成功后串口输出“Success”信息
        
    } else{    // 如果连接不成功则通过串口输出“连接失败”信息
        Serial.println(" connection failed!");
        client.stop();
        return ;
    }  
    
    if (!fb)
    {
        Serial.print("Camera capture failed");
    }
    else
    {
    	// 随机编码
        String randomCode = "";
        for( int i = 0 ; i < 10 ; i ++ ){
            // 生成随机编码
            switch ( random(0,3) ){
                case 0 :
                    randomCode += (char)random(48,58);
                    break;
                case 1 :
                    randomCode += (char)random(65,91);
                    break;
                case 2 :
                    randomCode += (char)random(97,123);
                    break;
            } 
        }

        String fileHead = "--" + randomCode  + "\r\n" +
                           "Content-Disposition: form-data; name=\"img\"; filename=\"" + randomCode + ".jpg\"" + "\r\n" +
                           "Content-Type: image/jpeg"  + "\r\n";
        // 获取文件大小
        size_t jpgsize = 0 ;
        for( jpgsize = 0 ; ;jpgsize++ ){
            if( fb->buf[jpgsize] == 0xff ){
                if( fb->buf[jpgsize+1] ==0xd9 ){
                    jpgsize += 2 ;
                    break;
                }
            }
        }
        // 发送文件头
        client.println("POST / HTTP/1.1");
        Serial.println("POST / HTTP/1.1");
        client.println("Host: "+ domain);
        Serial.println("Host: "+ domain);
        client.println("Content-Type: multipart/form-data; boundary=" + randomCode );
        Serial.println("Content-Type: multipart/form-data; boundary=" + randomCode );
        client.println("Connection: close");
        Serial.println("Connection: close");
        client.println("Content-Length: " + String( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2  ) );
        Serial.println("Content-Length: " + String( fileHead.length() + (jpgsize) + randomCode.length() + 4 + 2  ) );
        client.println("");
        Serial.println("");
        
        // 发送文件
        client.println( fileHead );
        Serial.println( fileHead );
        
        for (size_t i = 0; i < jpgsize; i++)
        {
            client.write(fb->buf[i]); // payload , lengte vd payload
        }
        // return the frame buffer back to the driver for reuse
        client.println("");
        client.print("--" + randomCode + "--");
        Serial.println("--" + randomCode + "--");
        // 清除摄像头缓存
        esp_camera_fb_return(fb);
        // 获取 API 返回报文
        rubbishMeg = "";
        while (client.connected() || client.available()){ 
            if (client.available()){
                char line = client.read();
                rubbishMeg += line ;
                Serial.print(line);
            }
        }
    }
    client.stop();     
}

联系作者

E-mail: Mr_Xie_@outlook.com
GitHub: https://github.com/MR-XieXuan
个人私站: https://main.mrxie.xyz/


?如果本文对您有帮助的话,可以给本文点一个赞👍或者是收藏本文📧。你的每一个赞可以给作者非常大的鼓励。
?如果遇到困难,欢迎联系作者,你可以私聊作者或者添加作者QQ、发送电子邮件向作者寻求帮助。也可以在下方评论区向大家提问。你的问题如果在评论区被解决也可以给其他遇到同样问题的一个参考。
作者不易,期待你的关注?。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 13:08:02  更:2022-10-17 13:09:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 3:41:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码