搜索
bottom↓
回复: 15

请问STM32+LAN+LWIP如何实现向HTTP接口发送大数据包?

[复制链接]

出3670入191汤圆

发表于 2024-2-4 12:57:59 | 显示全部楼层 |阅读模式
这应该是个纯软件问题。

我有个应用是通过STM32的虚拟U盘将电脑中的文件拷贝到STM32的EMMC中(单个文件从数MB到上GB),然后再通过STM32的以太网口上传到WEB后台。
(请别问为什么不通过电脑直接传而这么多此一举,问就是因为国情)

目前u盘的写入性能、fatfs的读取性能、tcp传输性能做单元测试都能满足性能要求了。

所问问题点在stm32向后台传输的性能问题。stm32无操作系统,直接用HAL框架。

我们开发人员不懂如何在单个http请求中发送超过tcp单帧数据包大小的请求体(也就是单请求只能发送一两k字节),目前的做法是发送一个大文件就需要拆成几千、几万甚至更多个http请求来发送。

这显然有明显的性能瓶颈,不是一种合理的方案。我知道http作为tcp的上层协议,它的单次请求额外开销是很大的,除了每次请求都要经过和服务器建立tcp连接三次握手,还要有http请求头和响应头的开销,以及http keep alive的处理。

我的嵌入式编程能力也是很弱的,所以想请教一下在stm32中如何实现像一般的HTTP请求中那样发送大量数据?

我纸上谈兵的想想,觉得要点在于实现emmc和eth两个外设的dma,以及如何和lwip的回调函数结合,实现一个尽量不间断的发送流水线,但还是觉得无从下手。

出100入312汤圆

发表于 2024-2-4 13:31:28 来自手机 | 显示全部楼层
一帧最大1500个字节,数据量大,必须分包,这和stm32无关,也说不上纸上谈兵,基本逻辑就有问题

出1310入193汤圆

发表于 2024-2-4 13:51:05 来自手机 | 显示全部楼层
分块传输(Chunked Transfer Encoding):
在HTTP头中添加 Transfer-Encoding: chunked 字段。
将文件分成小块,并分别发送每个小块。

尝试过么😘
   

出0入90汤圆

发表于 2024-2-4 14:03:58 | 显示全部楼层
本帖最后由 honami520 于 2024-2-4 14:06 编辑

http是处于tcp上层的内容,至于那个一帧1500字节,是物理层的内容。
你做软件,按照http去发就行了,分包发送,一包1KB,然后一直发完你想发的不就好了。
好比你用lwip,你直接按照发送内容,底层的事情交给底层去做就完了。
我用lwip几秒钟发送几百KB的内容,运行很正常,一天多少GB

出0入0汤圆

发表于 2024-2-4 14:20:31 | 显示全部楼层
web文件数据传输应该用FTP比较好把,FTP支持断点续传,可靠性强等优点;网上也有stm32移植FTP的例子,也比较好移植把;

http协议需要自己写文件的分包协议把,http是无状态协议,多个http请求到达服务器的顺序不一定是有序的;如果某一包后到服务器或者先到服务器就有问题,除非一包一包的发数据吗?

出3670入191汤圆

 楼主| 发表于 2024-2-4 14:29:11 | 显示全部楼层
lb0857 发表于 2024-2-4 13:51
分块传输(Chunked Transfer Encoding):
在HTTP头中添加 Transfer-Encoding: chunked 字段。
将文件分 ...
(引用自3楼)

这个机制不是用来处理我所说的问题的。

出3670入191汤圆

 楼主| 发表于 2024-2-4 14:47:27 | 显示全部楼层
honami520 发表于 2024-2-4 14:03
http是处于tcp上层的内容,至于那个一帧1500字节,是物理层的内容。
你做软件,按照http去发就行了,分包发 ...
(引用自4楼)

不知道你说的分包发送,是指一个http请求分成多个tcp包发送,还是直接分包成多个http请求?

lwip有高层的http接口吗?现在负责开发的人是自己用tcp封装了一个http请求出来,但是解决不了分成多个一个http分成多个tcp包发送的难题。

因为要传输的文件很大,分包是必须分包的,但是我不想分包到1536byte这么小的包。

比如一个HTTP POST请求体大致如下:

  1. POST /server-url HTTP/1.0
  2. HOST: www.example.com
  3. Cookie: ....
  4. Content-Length: 12345678
  5. Content-Type: multipart/form-data

  6. DATADATADATADATA...[省略10MB]
复制代码


包越小,HTTP请求头和其他协议开销占比越大,效率越低。

另,上面的请求是自己构造出来的,比如请求头和请求体的结构是根据规范拼接出来的,但是请求体中的文件数据是从EMMC读出来的。
难点是:
1. 因为内存一共就几十k很有限,所以需要边拼装边传输。
2. 为了提高传输效率,充分利用stm32非常有限的外设连接速度,那么就最好能同时读emmc和传tcp,那我能想到的就是用dma了。如果读一下emmc再传一下eth吗,那等于打对折的效率。
3. 我不知道lwip有现成可用的满足上面要求的http客户端高级接口,我觉得只能自己封装,那么就需要上述2点和lwip回调函数相配合,在回调时,能给lwip的发送缓冲区中及时填装数据。

在java中,这种一般通过stream接口来实现,但是在stm32中如何搞就没头绪了。

可能我的思路本身就和嵌入式不兼容吧。

出3670入191汤圆

 楼主| 发表于 2024-2-4 14:51:12 | 显示全部楼层
26消费者 发表于 2024-2-4 14:20
web文件数据传输应该用FTP比较好把,FTP支持断点续传,可靠性强等优点;网上也有stm32移植FTP的例子,也比 ...
(引用自5楼)

我们现在就是分成1k多的小包的,服务器收到多个小包后再拼起来。顺序错乱可以通过自己传输一个包顺序来解决的。
所以你说的问题可以解决。

至于FTP,它在很多场合下是不方便的,因为大型机构的防火墙一般是不会开放ftp端口的,但是开放80端口就很正常。

况且ftp还存在主动模式(20/21端口)和被动模式(21+动态端口),对防火墙配置来说非常不友好。

出3670入191汤圆

 楼主| 发表于 2024-2-4 14:54:52 | 显示全部楼层
akey3000 发表于 2024-2-4 13:31
一帧最大1500个字节,数据量大,必须分包,这和stm32无关,也说不上纸上谈兵,基本逻辑就有问题 ...
(引用自2楼)

没有逻辑问题,只是我提的问题比较绕,我在7楼又补充描述了。😁

出0入0汤圆

发表于 2024-2-4 14:58:01 | 显示全部楼层
TCP最大不是1500字节一包,还有没做那么多缓存。我司发送升级包是把升级包按配置payload大小分(256,512Byte),每包有序号和校验,整个升级包也有校验码,支持断点续传。不过就是传几百KB东西。

出0入75汤圆

发表于 2024-2-4 16:40:56 | 显示全部楼层
Rabbitoose 发表于 2024-2-4 14:47
不知道你说的分包发送,是指一个http请求分成多个tcp包发送,还是直接分包成多个http请求?

lwip有高层 ...
(引用自7楼)

分块,把Content-Length: 12345678删除,加上Transfer-encoding: chunked,后面每一块是 块长度<CR><LF>数据<CR><LF>,最后一块长度是0<CR><LF>,对方就知道发完了,可以分块准备数据。

出0入90汤圆

发表于 2024-2-4 17:00:40 | 显示全部楼层
本帖最后由 honami520 于 2024-2-4 17:07 编辑
Rabbitoose 发表于 2024-2-4 14:51
我们现在就是分成1k多的小包的,服务器收到多个小包后再拼起来。顺序错乱可以通过自己传输一个包顺序来解 ...
(引用自8楼)


lwip里面有专门的http的例子,不过那个我当初用的时候,在发送完成,等应答的时候,偶尔会出现30秒超时。
后来我就直接用tcp,然后也是自己封包成http去发送、解析了。

整个通信过程就是用lwip里面的socket来实现的,具体的流程是:
1、首先把发送的数据,按照http要求来重新封包(其实就是增加一些头信息)
2、创建一个socket,然后去连接服务器
3、连接成功后,就按照1KB来不断的write(lwip里面的函数),直到write完成
4、发送完成后,就不断read,直到读取到内容,或者超时退出

LWIP里面也有个缓存的,并不是我每次write 1KB进去,它就会马上发送出去。它也会攒一些数据,然后才真正去执行底层发送。
我一次write 10-20KB,对我来说效果也都是差不多的。因为跑lwip的时候肯定是用RTOS了。
那个1500字节,你不用特别在意,人家都给你想好了的

而且tcp通信,根本不存在你说的多个小包拼起来,它是连续的。不过网络不好的时候也许会出现一些特殊情况,丢数据也是有可能。
但是网络正常的时候,根本不存在顺序错乱

出0入148汤圆

发表于 2024-2-4 17:01:53 | 显示全部楼层
Rabbitoose 发表于 2024-2-4 14:51
我们现在就是分成1k多的小包的,服务器收到多个小包后再拼起来。顺序错乱可以通过自己传输一个包顺序来解 ...
(引用自8楼)

不懂为何包要分这么小,tcp本来就是流,你发了http头后后面就是emmc到tcp流的数据拷贝传输,没有说一定要在一个ip帧里面

出3670入191汤圆

 楼主| 发表于 2024-2-4 19:57:08 | 显示全部楼层
honami520 发表于 2024-2-4 17:00
lwip里面有专门的http的例子,不过那个我当初用的时候,在发送完成,等应答的时候,偶尔会出现30秒超时。 ...
(引用自12楼)

那你一般能达到多少传输速度呢?我现在大约有3MB的样子,我主要的目的是提高速度。

出300入477汤圆

发表于 2024-2-4 21:11:23 来自手机 | 显示全部楼层
honami520 发表于 2024-2-4 14:03
http是处于tcp上层的内容,至于那个一帧1500字节,是物理层的内容。
你做软件,按照http去发就行了,分包发 ...

(引用自4楼)

对。
网卡一包1.5K和http一个请求能装多少,根本就没有一点关系。
http只能看到tcp的数据流,
tcp才能看到下面一层是网卡的数据帧。
http发请求只是调用tcp层,传递一个数据流,长度自己决定。你可以一边生成数据,一边往下写,跟你内存大小都没关系。你可以一下子生成差不多快装满内存的数据,然后发完,继续再生成就是。
如果预先不知道数据长度,有两招,一个是上面说的chunked,还有另一招是改成http1.0,不带content-length,而是发完数据了就关闭连接。这样更简单。

出0入42汤圆

发表于 2024-2-5 00:59:30 来自手机 | 显示全部楼层
本帖最后由 albert_w 于 2024-2-5 01:00 编辑

http上传,做好头部和尾部中间文件流往上传就可以了,中间就纯tcp包。头部有分隔符来识别http结束的

问题是如果文件太大网络不好,还是要对http分包,把文件割成多块上传。失败哪块传哪块。至于块多大看你文件和网络了。1xxx肯定不合适,太碎了,比如128k甚至几M
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-5 16:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表