lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示

这篇具有很好参考价值的文章主要介绍了lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

本教程使用的单片机是STM32F103ZE,有线网口芯片为ENC28J60。
本教程里面的网页由于需要兼容Windows XP系统的IE8浏览器,所以采用HTML 4.01编写,不使用任何前端框架。笔者使用的网页设计软件是Adobe Dreamweaver CS3。
开发板PCB文件是公开的,大家可以拿去打印出来,焊好器件后,就可以直接跑本教程提供的所有示例程序。
示例程序和PCB板的下载地址为:https://pan.baidu.com/s/1vT5Le1qauh5uTNfu8xKXzQ(提取码:k6tz)

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32


lwip-2.1.3在STM32F103ZE+ENC28J60有线网卡上无操作系统移植(使用STM32 HAL库)_lwip stm32f103_巨大八爪鱼的博客-CSDN博客一、概述以太网芯片简介ENC28J60是一款10Mbps速率的以太网MAC+PHY芯片,和单片机的通信接口为SPI,SPI最高时钟频率为20MHz。ENC28J60支持半双工和全双工模式,但是不支持自动协商。在支持自动协商的网络环境中,ENC28J60默认的工作模式是半双工模式。另外,STM32本身有一个ETH外设,这个外设采用的接口是MII或RMII,不是SPI,所以不能连接ENC28J60芯片,这次我们用不到这个ETH外设。STM32本身的ETH外设相当于MAC,通常要外接一个PHY芯片(_lwip stm32f103lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32https://blog.csdn.net/ZLK1214/article/details/121419417

makefsdata程序的使用

默认情况下,lwip httpd服务器使用的网页文件来源于lwip-2.1.3/apps/http/fsdata.c。
fsdata.c是由lwip自带的makefsdata程序将lwip-2.1.3/apps/http/fs里面的所有文件打包后得到的。
lwip只提供了makefsdata程序的C语言源代码,如果想要在Windows系统上运行,需要用Visual Studio编译代码,生成exe文件,放到http目录下(也就是有fs文件夹的目录下),双击即可使用。编译的方法请参考下面这篇文章。
(本文例程里面已经放好了编译好的makefsdata程序,可直接使用,不用再自己重新编译)
在Visual Studio 2012下编译lwip-2.1.3 httpd的makefsdata_makefsdata.exe_巨大八爪鱼的博客-CSDN博客步骤一 建立空白工程新建一个工程,项目名称起名为makefsdata。因为mkfsdata是一个控制台程序,所以我们要选择Win32 Console Application。这里很重要,必须要勾选“Empty Project”选项,建立空项目:建好的解决方案目录是C:\Users\Octopus\Desktop\makefsdata,工程目录是C:\Users\Octopus\Desktop\makefsdata\makefsdata。步骤二 解压lwip-2.1.3的部分头文件和_makefsdata.exelwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32https://blog.csdn.net/ZLK1214/article/details/122490482双击运行makefsdata程序后,程序自动将fs文件夹下的所有内容打包成一个fsdata.c文件。每次修改完fs文件夹里面的网页文件和图片后,只需要重新运行makefsdata程序,就能打包生成新的fsdata.c文件。

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

STM32的Keil工程里面只需要添加fs.c和httpd.c这两个C文件,不能把fsdata.c添加到Keil工程里面去。这是因为fs.c里面用#include指令包含了fsdata.c文件。

#define HTTPD_FSDATA_FILE "fsdata.c" // httpd_opts.h
#include HTTPD_FSDATA_FILE // fs.c

fsdata.c也可以改成其他自己喜欢的名字,把扩展名改成.h都行,改名后要把新的文件名定义到lwipopts.h中(注意不是改fs.c或者httpd_opts.h)。新命名的文件同样不能添加到Keil工程中。

#define HTTPD_FSDATA_FILE "fsdata_custom.h"

fsdata.c里面以C语言数组的形式保存了fs文件夹下的所有文件,包括html文件和图片文件,以及其他类型的文件。zip、rar压缩包,还有exe文件都可以放进去,用户用浏览器访问这些非网页文件的时候,浏览器不会直接显示这些文件的内容,而是启动下载工具,把文件下载下来,让用户选择一个电脑上的文件夹保存。
当用户通过浏览器访问一个不存在的网页时,lwip会自动重定向到404.html错误页面。
Keil工程编译并烧写到STM32单片机后,最终这些网页内容是保存到STM32单片机的Flash中的。STM32单片机的Flash容量是有限的,只有几百KB~几MB,能存放的网页文件非常有限。如果网页个数非常多,非常大,Flash放不下的话,就得想其他的办法。

动态加载SD卡上的网页文件(一次性加载)

(本节例程名称:webpages_from_sdcard)
既然STM32本身的Flash放不下网页文件,那我们可以外接一个SPI Flash(如W25Q128)或者一张SD卡来保存网页文件。如果用SD卡的话,能保存的网页文件就非常多了,保存一个几百兆的压缩包供用户下载都不是问题。
存储器可以使用FAT、FAT32或者exFAT文件系统,以文件的形式存储网页文件。STM32通过FatFS读取存储器中存储的文件。
笔者是把所有的网页文件放到SD卡的www目录下,如下图所示。(例程里面运行了一个ftp服务器,可以在线访问SD卡中的文件,还可以在线往SD卡里面上传文件)

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

要想让lwip的httpd服务器从SPI Flash或SD卡上动态加载网页文件并显示的话,需要在lwipopts.h中定义下面两个宏。

// 配置HTTPD
#define LWIP_HTTPD_CUSTOM_FILES 1
#define LWIP_HTTPD_DYNAMIC_HEADERS 1

然后我们需要自己实现下面两个接口函数。

int fs_open_custom(struct fs_file *file, const char *name);
void fs_close_custom(struct fs_file *file);

fs_open_custom函数的功能是读取指定的网页文件的内容。函数返回1表示文件读取成功,返回0表示文件读取失败。
fs_close_custom函数的功能是释放fs_open_custom函数里面分配的内存块,关闭已打开的文件。

我们新建一个webpages_test.c文件,在里面实现这两个函数。

#include <ff.h>
#include <lwip/apps/fs.h>
#include <lwip/mem.h>
#include <string.h>

int fs_open_custom(struct fs_file *file, const char *name)
{
  char path[260];
  int i, size;
  int ret = 0;
  void *mem;
  FIL *fp;
  FRESULT fr;
  UINT br;
  
  // name为要访问的网页URL, 是相对路径, 将其转换成绝对路径
  snprintf(path, sizeof(path), "C:\\www%s", name);
  for (i = 0; path[i] != '\0'; i++)
  {
    if (path[i] == '/')
      path[i] = '\\';
  }
  if (path[i - 1] == '\\' && sizeof(path) - i >= 10 + 1)
    strcat(path, "index.html");
  
  fp = mem_malloc(sizeof(FIL));
  if (fp != NULL)
  {
    fr = f_open(fp, path, FA_READ); // 打开文件
    if (fr == FR_OK)
    {
      size = f_size(fp); // 获取文件大小
      mem = mem_malloc(size);
      if (mem != NULL)
      {
        f_read(fp, mem, size, &br); // 一次性读完整个文件
        
        file->data = mem; // 要显示的网页内容
        file->pextension = mem; // http连接关闭时要在fs_close_custom()函数中释放的内存块
        file->len = size; // 要显示的网页内容的长度
        file->index = size; // 要显示的网页内容的长度
        printf("%s(0x%p): %s\n", __func__, file->pextension, path);
        ret = 1;
      }
      f_close(fp); // 关闭文件
    }
    mem_free(fp);
  }
  // 函数返回1表示网页文件存在, 返回0表示网页文件不存在
  // 网页文件不存在时httpd会去加载lwip-2.1.3/apps/http/makefsdata里面的默认网页
  return ret;
}

void fs_close_custom(struct fs_file *file)
{
  printf("%s(0x%p)\n", __func__, file->pextension);
  if (file->pextension != NULL)
  {
    mem_free(file->pextension);
    file->pextension = NULL;
  }
}

fs_open_custom函数的name参数的值跟浏览器里面访问的网址有关。如果浏览器访问的网址是http://stm32f103ze/entertainment.html,那么name="/entertainment.html"。
在上面的程序中,将name与“C:\www”字符串拼接(C语言中字符串里面的反斜杠要双写),再把所有的正斜杠替换成反斜杠,就得到了“C:\www\entertainment.html”这个路径,打开的是SD卡www文件夹下的entertainment.html文件。如果浏览器访问的是一个文件夹,则自动在后面追加index.html,实际访问的是这个文件夹下的index.html文件。
把文件路径保存到path字符数组中,用FatFs的f_open函数以只读的方式打开网页文件,再用f_size函数获取网页文件的大小(size)。
用lwip的mem_malloc函数分配size大小的内存,接着用f_read函数把整个文件的内容一次性读取到新分配的这块内存里面。
把保存有网页内容的内存块指针mem赋给file->data,网页的大小赋给file->len和file->index这两个成员,lwip的httpd服务器就能显示SD卡上的网页了。
mem内存块会在fs_open_custom函数执行完毕后由lwip使用,所以mem内存块不能在fs_open_custom函数里面释放,那在哪里释放呢?fs_close_custom函数就是用来完成这个任务的。
我们把mem内存块的地址赋给file->pextension成员,lwip不会使用file->pextension这个成员变量,变量的值可以随便定义。
lwip发送完全部网页内容后就会调用fs_close_custom函数,在这个函数中用file->pextension访问刚才的mem内存块,用mem_free函数回收内存。

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

 lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

 lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

 lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

如果访问了sd卡上不存在的网页,则fs_open_custom函数返回0,lwip会去makefsdata的fs文件夹里面寻找,如果还是没找到,则会显示makefsdata的404.html错误页面。

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

串口打印:

STM32F103ZE ENC28J60
SystemCoreClock=72000000
LSE is ON!
MAC address: 00:12:34:56:78:90
ENC28J60 ID: 0x0083 0x1400
IPv6 link-local address: FE80::212:34FF:FE56:7890
SD init OK! frequency=24MHz
SDCard type: SDHC/SDXC
SDCard version: V2
SDCard block number: 121634816
SDCard block size: 512
SDCard capacity: 59392MB
Disk is mounted!
Link is up!
[Send] len=350
[Recv] len=60, next=70
[Recv] len=590, next=670
[Send] len=350
[Recv] len=590, next=1270
[Send] len=42
[Send] len=42
[Send] len=86
[Send] len=78
[Send] len=62
[Send] len=42
[Send] len=86
[Send] len=42
DHCP supplied address!
IP address: 192.168.1.102
Subnet mask: 255.255.255.0
Default gateway: 192.168.1.1
DNS Server: 192.168.1.1
[Send] len=42
[Send] len=42
[Recv] len=60, next=1340
[Send] len=72
[Recv] len=136, next=1486
[Send] len=90
[Send] len=86
[Recv] len=90, next=1586
Time from network: 2023-07-13 13:06:57
RTC is not updated
[Send] len=42
[Recv] len=60, next=1656
[Send] len=42
[Send] len=42
[Send] len=70
[Recv] len=142, next=1808
[Send] len=86
[Recv] len=86, next=1904
[Recv] len=92, next=2006
[Send] len=42
[Recv] len=60, next=2076
[Send] len=104
[Recv] len=62, next=2148
[Send] len=62
[Recv] len=60, next=2218
[Recv] len=332, next=2560
fs_open_custom(0x60000468): C:\www\index.html
[Send] len=1514
[Send] len=147
[Recv] len=60, next=2630
fs_close_custom(0x60000468)
[Send] len=1514
[Send] len=1298
[Recv] len=62, next=2702
[Send] len=62
[Recv] len=60, next=2772
[Recv] len=60, next=2842
[Send] len=54
[Recv] len=60, next=2912
[Recv] len=392, next=3314
fs_open_custom(0x600003d4): C:\www\resources\mm_lodging_image.jpg
[Send] len=1514
[Send] len=148
[Recv] len=60, next=3384
[Send] len=1514
[Send] len=1514
[Recv] len=60, next=3454
fs_close_custom(0x600003d4)
[Send] len=1514
[Send] len=135
[Recv] len=60, next=3524
[Recv] len=60, next=3594
[Send] len=54
[Send] len=78
IPv6 address 1: 2409:8A62:3EA:6110:212:34FF:FE56:7890
DNS Server: FE80::1
[Send] len=86
[Recv] len=60, next=3664
[Recv] len=86, next=3760
[Send] len=86
[Recv] len=60, next=3830
[Recv] len=60, next=3900

这种方法是把整个网页文件一次性读取到单片机的SRAM内存中,再由lwip httpd通过网络发送给浏览器显示。
要是网页文件很大,SRAM一次性放不下,那就只有换一种分多次读取的方法了。

动态加载SD卡上的网页文件(分多次读取)

(本节例程名称:webpages_from_sdcard_discontinuously)
如果想要多次读取同一个网页文件,可以在lwipopts.h中定义LWIP_HTTPD_DYNAMIC_FILE_READ=1,然后实现int fs_read_custom(struct fs_file *file, char *buffer, int count)函数。

// 配置HTTPD
#define LWIP_HTTPD_CUSTOM_FILES 1
#define LWIP_HTTPD_DYNAMIC_FILE_READ 1
#define LWIP_HTTPD_DYNAMIC_HEADERS 1
#include <ff.h>
#include <lwip/apps/fs.h>
#include <lwip/mem.h>
#include <string.h>

struct file_content
{
  FIL fil;
  char buffer[2500];
  int pos;
};

int fs_open_custom(struct fs_file *file, const char *name)
{
  char path[260];
  int i, ret = 0;
  struct file_content *content;
  FRESULT fr;
  
  // name为要访问的网页URL, 是相对路径, 将其转换成绝对路径
  snprintf(path, sizeof(path), "C:\\www%s", name);
  for (i = 0; path[i] != '\0'; i++)
  {
    if (path[i] == '/')
      path[i] = '\\';
  }
  if (path[i - 1] == '\\' && sizeof(path) - i >= 10 + 1)
    strcat(path, "index.html");
    
  content = mem_malloc(sizeof(struct file_content));
  if (content != NULL)
  {
    content->pos = 0;
    fr = f_open(&content->fil, path, FA_READ); // 打开文件
    if (fr == FR_OK)
    {
      // 网页文件存在
      file->len = sizeof(content->buffer); // 指定fs_read_custom()函数的count参数的最大值(不能设置为0)
      file->pextension = content; // 保存分配的内存指针, http连接关闭时才释放
      printf("%s(0x%p): %s\n", __func__, content, path);
      ret = 1;
    }
    else
    {
      // 网页文件不存在
      mem_free(content);
      content = NULL;
    }
  }
  // 函数返回1表示网页文件存在, 返回0表示网页文件不存在
  // 网页文件不存在时httpd会去加载lwip-2.1.3/apps/http/makefsdata里面的默认网页
  return ret;
}

void fs_close_custom(struct fs_file *file)
{
  struct file_content *content = file->pextension;
  
  printf("%s(0x%p)\n", __func__, content);
  if (content != NULL)
  {
    f_close(&content->fil); // 关闭文件
    mem_free(content); // 释放内存
    file->pextension = NULL;
  }
}

int fs_read_custom(struct fs_file *file, char *buffer, int count)
{
  struct file_content *content = file->pextension;
  UINT br;
  
  // count为要读取的字节数, br为实际读取到的字节数
  f_read(&content->fil, buffer, count, &br);
  if (br == 0)
  {
    // 文件读取完毕
    printf("%s(0x%p): end of file\n", __func__, content);
    return FS_READ_EOF;
  }
  printf("%s(0x%p): %d~%d\n", __func__, content, content->pos, content->pos + br - 1);
  content->pos += br;
  return br;
}

网页访问效果和之前的程序一样,只不过串口打印有区别。在串口中可以看到,一个文件可以分多次读取。

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

在fs_open_custom函数中,只需要打开文件,把f_open返回的FIL对象保存到file->pextension里面就行,不需要读取文件内容,也不需要获取文件的总大小。file->len成员要赋值,这个值指定的是后面fs_read_custom()函数的count参数的最大值,不允许设置为0。
fs_read_custom函数用于分多次读取文件的内容。参数buffer是保存文件内容的缓冲区,count是缓冲区的大小。函数的返回值是本次实际读取到的文件内容的长度,返回值应该大于0,且小于或等于count。若文件已经读取完毕了,没有更多文件内容了,则应该保持buffer缓冲区的内容不变,函数返回FS_READ_EOF。lwip收到FS_READ_EOF这个返回值后,就会调用fs_close_custom函数关闭文件,在fs_close_custom函数中应该用f_close函数关闭文件,还要把FIL对象占用的内存释放掉。
当LWIP_HTTPD_DYNAMIC_FILE_READ=1时,一次性读取文件的程序和分多次读取文件的程序可以在同一个项目里面共存。为了防止编译报错,一次性读取文件的程序需要实现一个空的fs_read_custom函数,函数直接返回FS_READ_EOF就行。程序实际运行中,lwip httpd并不会调用fs_read_custom函数,只调用fs_open_custom和fs_close_custom函数。
一次性读取文件的程序和分多次读取文件的程序的区别:

file->data file->pextension file->len file->index fs_read_custom函数
一次性读取文件 完整的文件内容 程序自定义 文件的总大小 文件的总大小 不需要实现,即使实现了也不会被调用
分多次读取文件 NULL 程序自定义 fs_read_custom函数每次最多读取多少字节的内容 无需赋值 需要实现

动态生成虚拟网页文件

lwip给了我们从磁盘上读取网页文件的接口,但是我们在实现这些接口函数的时候不一定非要老老实实真的从磁盘上去读取文件。我们完全可以随便在内存里面动态生成一张网页,直接交给lwip httpd去显示。

一次性动态生成一整张网页:
(本节例程名称:virtual_webpage)

#include <lwip/apps/fs.h>
#include <lwip/mem.h>
#include <string.h>
#include <time.h>

#define N 1000

int fs_open_custom(struct fs_file *file, const char *name)
{
  char *str;
  char timestr[30];
  int i;
  struct tm tm;
  time_t t;
  unsigned long values[10];
  
  if (strcmp(name, "/helloworld.html") == 0)
  {
    str = mem_malloc(N);
    if (str == NULL)
      return 0;
    
    time(&t);
    localtime_r(&t, &tm);
    strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &tm);
    for (i = 0; i < 10; i++)
      values[i] = rand();
    
    snprintf(str, N, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
                     "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n"
                     "<html>\r\n"
                     "<head>\r\n"
                     "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=gb2312\">\r\n"
                     "<title>随机数</title>\r\n"
                     "<style>\r\n"
                     "body {\r\n"
                     "\tfont-family: Arial;\r\n"
                     "\tsize: 14px;\r\n"
                     "}\r\n"
                     "\r\n"
                     ".red {\r\n"
                     "\tcolor: red;\r\n"
                     "}\r\n"
                     "</style>\r\n"
                     "</head>\r\n"
                     "\r\n"
                     "<body>\r\n"
                     "<b>当前时间:</b> %s<br>\r\n"
                     "<b>随机数1:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数2:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数3:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数4:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数5:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数6:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数7:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数8:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数9:</b> <span class=\"red\">0x%08lx</span><br>\r\n"
                     "<b>随机数10:</b> <span class=\"red\">0x%08lx</span>\r\n"
                     "</body>\r\n"
                     "</html>\r\n",
             timestr, values[0], values[1], values[2], values[3], values[4], 
             values[5], values[6], values[7], values[8], values[9]
    );
    
    file->data = str;
    file->pextension = str;
    file->len = strlen(str);
    file->index = file->len;
    printf("%s(0x%p)\n", __func__, file->pextension);
    return 1;
  }
  else
    return 0;
}

void fs_close_custom(struct fs_file *file)
{
  printf("%s(0x%p)\n", __func__, file->pextension);
  if (file->pextension != NULL)
  {
    mem_free(file->pextension);
    file->pextension = NULL;
  }
}

#if LWIP_HTTPD_DYNAMIC_FILE_READ
// 实现此函数是为了在LWIP_HTTPD_DYNAMIC_FILE_READ=1的环境下不报错
// 程序运行时, 此函数不会被调用
int fs_read_custom(struct fs_file *file, char *buffer, int count)
{
  return FS_READ_EOF;
}
#endif

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

每次刷新网页,页面上显示的日期时间,以及10个随机数的值都不相同。

分多次生成一张网页(占用的内存很小):
(本节例程名称:virtual_webpage2)

#include <lwip/apps/fs.h>
#include <lwip/mem.h>
#include <string.h>
#include <time.h>

#define MAXSTEP 25

struct content
{
  char str[4000];
  int step;
  int pos;
  int len;
  int tot_len;
  int id;
};

int fs_open_custom(struct fs_file *file, const char *name)
{
  struct content *content;
  
  if (strcmp(name, "/helloworld.html") == 0)
  {
    content = mem_malloc(sizeof(struct content));
    if (content == NULL)
      return 0;
    memset(content, 0, sizeof(struct content));
    content->id = 1;
    
    file->len = sizeof(content->str); // 指定fs_read_custom()函数的count参数的最大值(不能设置为0)
    file->pextension = content;
    printf("%s(0x%p)\n", __func__, file->pextension);
    return 1;
  }
  else
    return 0;
}

void fs_close_custom(struct fs_file *file)
{
  printf("%s(0x%p)\n", __func__, file->pextension);
  if (file->pextension != NULL)
  {
    mem_free(file->pextension);
    file->pextension = NULL;
  }
}

int fs_read_custom(struct fs_file *file, char *buffer, int count)
{
  char part[70];
  int i;
  struct content *content = file->pextension;
  struct tm tm;
  time_t t;
  unsigned long value;
  
  if (content->pos == 0)
  {
    if (content->step == 0)
    {
      time(&t);
      localtime_r(&t, &tm);
      strftime(part, sizeof(part), "%Y-%m-%d %H:%M:%S", &tm);
      snprintf(content->str, sizeof(content->str),
        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
        "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n"
        "<html>\r\n"
        "<head>\r\n"
        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=gb2312\">\r\n"
        "<title>随机数</title>\r\n"
        "<style>\r\n"
        "body {\r\n"
        "\tfont-family: Arial;\r\n"
        "\tsize: 14px;\r\n"
        "}\r\n"
        "\r\n"
        ".red {\r\n"
        "\tcolor: red;\r\n"
        "}\r\n"
        "</style>\r\n"
        "</head>\r\n"
        "\r\n"
        "<body>\r\n"
        "<b>当前时间:</b> %s<br>\r\n", part);
    }
    else if (content->step < MAXSTEP)
    {
      i = 0;
      content->str[0] = '\0';
      while (i < sizeof(content->str) / sizeof(part))
      {
        value = rand();
        snprintf(part, sizeof(part), "<b>随机数%d:</b> <span class=\"red\">%lu</span><br>\r\n", content->id + i, value);
        i++;
        if (strlen(content->str) + strlen(part) + 1 > sizeof(content->str))
        {
          printf("%s: buffer is too small\n", __func__);
          break;
        }
        strcat(content->str, part);
      }
      content->id += i;
      printf("%s: step=%d, id=%d~%d\n", __func__, content->step, content->id, content->id + i - 1);
    }
    else if (content->step == MAXSTEP)
      strcpy(content->str, "</body>\r\n</html>\r\n");
    else
    {
      printf("%s(0x%p): end of file, tot_len=%d\n", __func__, content, content->tot_len);
      return FS_READ_EOF;
    }
    content->len = strlen(content->str);
    content->tot_len += content->len;
  }
    
  if (count > content->len - content->pos)
    count = content->len - content->pos;
  printf("%s(0x%p): step=%d, len=%d, current=%d~%d\n", __func__, content, content->step, content->len, content->pos, content->pos + count - 1);
  memcpy(buffer, content->str + content->pos, count);
  content->pos += count;
  if (content->pos == content->len)
  {
    content->step++;
    content->pos = 0;
  }
  return count;
}

lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示,STM32,服务器,http,web,lwip,stm32

当MAXSTEP=25时,我们仅仅用了4000字节的str缓冲区就成功生成了一张大小为80658字节的网页,显示了1368个随机数。网页大小还可以更大,只不过IE浏览器会卡死。
我们后面还将学习利用URL参数动态控制MAXSTEP的值,也就是在网址后面追加参数,例如:http://XXX/helloworld.html?maxstep=40。
lwip httpd的CGI功能就是专门用来解析URL参数的,解析出来后存到file->pextension的结构体里面,就可以在fs_read_custom中使用了。用户就可以随便指定MAXSTEP的大小,在程序运行时动态控制网页中显示的随机数的数量。

下一篇:lwip-2.1.3自带的httpd网页服务器使用教程(二)使用SSI动态生成网页部分内容文章来源地址https://www.toymoban.com/news/detail-555919.html

到了这里,关于lwip-2.1.3自带的httpd网页服务器使用教程(一)从SD卡读取网页文件并显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【httpd】 Apache http服务器目录显示不全解决

    可通过find查找文件所在位置 其中 FancyIndexing 支持美化显示; HTMLTable 允许底层代码把文件列表生成在一个table元素里面; VersionSort 安装版本排序; NameWidth=* 页面自动匹配文件名宽度; FoldersFirst 安装文件夹优先排列; Charset=UTF-8 支持中文显示; SuppressDescription 不显示文件描述

    2024年02月08日
    浏览(44)
  • 使用代理服务器导致电脑无法打开网页解决办法

    日常生活和工作中,经常会使用代理IP。但是在使用完代理服务器之后,很多用户都会遇到这样的问题:明明网络正常,为什么网页确打不开了? 其实,只需要关闭代理服务即可。具体操作如下: win+i进入设置 进入【网络和Internet】 进入【代理】 关闭【使用代理服务器】选

    2024年02月11日
    浏览(70)
  • ESP32作为服务器,使用网页控制LED小灯

    项目描述 ESP32-S开发板加入局域网,使用platformIO编写好ESP32的代码后,编译下载到ESP32中,访问ESP32的IP地址,使用网页控制连接着的LED小灯 项目准备: ESP32-S开发板 一根数据线 电脑 LED小灯 开发环境:vscode + PlatformIO 原理剖析 这个ESP32作为服务器,浏览器作为客户端,这是一个简

    2023年04月26日
    浏览(54)
  • linux 15day apache apache服务安装 httpd服务器 安装虚拟主机系统 一个主机 多个域名如何绑定

    1.apache目录介绍 1.准备测试页面 2.访问控制测试 可以直接编辑apache主配置文件 修改默认网站发布目录 配置域名解析: 测试访问 基于端口 访问:www.soso666.com 访问: test.soso666.com:81 可以配置域名解析,也可以不用配域名解析

    2024年02月04日
    浏览(53)
  • 【小沐学Python】各种Web服务器汇总(Python、Node.js、PHP、httpd、Nginx)

    web 服务器一词可以代指硬件或软件,或者是它们协同工作的整体。 基本上,当浏览器需要一个托管在网络服务器上的文件的时候,浏览器通过 HTTP 请求这个文件。当这个请求到达正确的 web 服务器(硬件)时,HTTP 服务器(软件)收到这个请求,找到这个被请求的文档(如果

    2024年02月07日
    浏览(79)
  • 4.物联网LWIP之C/S编程,实现服务器大小写转换

    LWIP配置 服务器端实现 客户端实现 错误分析 一。LWIP配置(FREERTOS配置,ETH配置,LWIP配置) 1.FREERTOS配置  为什么要修改定时源为Tim1?不用systick? 原因:HAL库与FREERTOS都需要使用systick,两者冲突,所以修改时钟源,让FREERTOS使用Tim1。  2.ETH配置  3.LWIP配置 不使用DHCP  4.步骤

    2024年02月12日
    浏览(44)
  • RT-Thread Studio配置LAN8720+LWIP+TCP服务器实现

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 由于项目上需要使用RT-Thread建立TCP服务器实现与客户端的数据交互,查阅了不少资料以及踩了不少坑,这里记录和分享一下实现的过程,希望能帮助到有需要的同学,您的支持是我创作的最大动力,谢谢

    2024年01月25日
    浏览(47)
  • Mac通过自带终端连接linux服务器

    在开发和系统管理中,经常需要通过远程连接到Linux服务器或终端来执行命令和管理任务。在Mac终端上使用SSH协议可以轻松实现与Linux系统的安全连接。本文将介绍如何在Mac终端上连接到Linux系统的简单步骤。 打开终端应用程序 在\\\"应用程序\\\"文件夹的\\\"实用工具\\\"目录下,找到并

    2024年02月16日
    浏览(45)
  • python自带静态web服务器搭建代码实现(一)

    一、静态web服务器 静态web法服务器: 可为发出请求的浏览器提供静态文档的程序,平时上网浏览的页面都是动态的,而开发的是静态的,页面数据不会发生变化 搭建python自带的静态web服务器 命令: python3 -m http.server 端口号 -m: 表示运行包里面的模块,执行该命令需进入指

    2024年02月03日
    浏览(53)
  • mysqladmin 管理 MySQL 服务器的系统自带的客户端工具

    mysqladmin 是一个客户端工具用来 执行管理操作 。你可以用它来检查服务器的配置、当前状态、创建或删除数据库等等 语法如下: 有很多的命令,只列举一些常见的命令,如下: create * db_name * Create a new database named * db_name * drop * db_name * Delete the database named * db_name * and all its

    2024年02月11日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包