0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

第九章 W55MH32 HTTP Server示例

W55MH32 来源:W55MH32 作者:W55MH32 2025-07-24 09:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机

W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm® Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。

在封装规格上,W55MH32提供了两种选择:QFN100和QFN68。

W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入http://www.w5500.com/网站或者私信获取。

此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。

为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。

若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页:http://www.w5500.com/,我们期待与您共同探索W55MH32的无限可能。

wKgZO2iBiluAVPzhAACkXwEtdxk292.png

第九章 W55MH32 HTTP Server示例

本篇文章我们将详细介绍如何在W55MH32芯片上面实现HTTP Server功能,并通过实战例程,为大家讲解如何通过浏览器修改W55MH32的网络地址信息。

该例程用到的其他网络协议,例如DHCP,请参考相关章节。有关W55MH32的初始化过程,也请参考相关章节,这里将不再赘述。

1 HTTP协议简介

HTTP(超文本传输协议,HyperText Transfer Protocol)是一种用于分布式、协作式、超媒体信息系统的应用层协议,基于 TCP/IP通信协议来传递数据,是万维网(WWW)的数据通信的基础。设计 HTTP最初的目的是为了提供一种发布和接收 HTML页面的方法,通过 HTTP或者 HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。

以上是HTTP协议的简介,如想深入了解该协议,请参考mozilla网站上的介绍: HTTP 概述 - HTTP | MDN

2 HTTP协议特点

基于请求-响应模型:客户端发起请求,服务器处理后返回响应。例如,用户在浏览器输入网址时,浏览器会向对应服务器发送HTTP请求,服务器返回网页内容。

无状态性:HTTP本身不保存请求之间的状态,每次请求独立。但可以通过Cookie、Session等机制实现状态保持。

无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求并收到客户的应答后,便立即断开连接。

3 HTTP Server应用场景

W55MH32使用HTTP Server模式可以进行以下几种应用:

设备配置和管理:通过浏览器访问W55MH32提供的WEB界面,实现网络配置,系统参数调整,固件升级等操作。

实时监控和数据展示:通过浏览器访问W55MH32提供的WEB页面,实时监控传感器数据,状态信息,以及查看工作日志等。

远程控制:通过浏览器访问W55MH32提供的WEB页面进行远程控制设备,如开关等。

4 HTTP协议的基本工作流程

HTTP的请求-响应模型通常由以下几个步骤组成

建立连接:客户端与服务器之间基于TCP/IP协议建立连接。

发送请求:客户端向服务器发送请求,请求中包含要访问的资源的 URL、请求方法(GET、POST、PUT、DELETE等)、请求头(例如,Accept、User-Agent)以及可选的请求体(对于 POST 或 PUT请求)。

处理请求:服务器接收到请求后,根据请求中的信息找到相应的资源,执行对应的处理操作。这可能涉及从数据库中检索数据、生成动态内容或者简单地返回静态文件。

发送响应:服务器将处理后的结果封装在响应中,并将其发送回客户端。响应包含状态码(用于指示请求的成功或失败)、响应头(例如,Content-Type、Content-Length)以及可选的响应体(例如,HTML页面、图像数据)。

关闭连接:在完成请求-响应周期后,客户端和服务器之间的连接将被关闭,除非使用了持久连接(如 HTTP/1.1中的 keep-alive)。

5 HTTP请求方法

在HTTP协议中,GETPOST是两种常用的请求方法,用于客户端向服务器发送数据和获取资源。

GET方法

GET方法通常用于从服务器获取资源。它有以下特点:

参数传递:请求参数通过URL中的查询字符串传递,形如?key1=value1&key2=value2。

数据大小限制:由于参数附加在URL后,长度可能受URL长度限制(取决于浏览器和服务器设置)。

安全性:数据在URL中明文显示,不适合传递敏感信息。

请求格式:

GET < Request-URI > HTTP/< Version >
< Headers >

Request-URI:表示目标资源的路径,可能包含参数。

Version:HTTP协议版本。

Headers:包含元信息,例如客户端的属性、支持的格式等。

Blank Line:空行。

POST方法

POST方法通常用于向服务器提交数据。它有以下特点:

参数传递:数据放在请求体中,而不是URL中。

数据大小限制:POST请求的体积没有明显限制,可以传递大量数据。

安全性:数据在请求体中传输,相对来说更安全。

请求格式:

POST < Request-URI > HTTP/< Version >
< Headers >

Request-URI:目标资源的路径,通常是API的端点。

Headers:元信息,例如内容类型和长度。

Blank Line:空行,区分头和主体。

Body:数据的主体,包含客户端发送到服务器的长度。

6 HTTP协议响应内容

HTTP协议响应内容包含状态行、响应头以及响应体三个部分。

状态行

HTTP状态行包含HTTP协议版本、状态码以及状态描述。

状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。

状态码分为五类:

1xx(信息性状态码):表示接收的请求正在处理。

2xx(成功状态码):表示请求正常处理完毕。

3xx(重定向状态码):需要后续操作才能完成这一请求。

4xx(客户端错误状态码):表示请求包含语法错误或无法完成。

5xx(服务器错误状态码):服务器在处理请求的过程中发生了错误。

示例:

HTTP/1.1 200 OK

响应头

响应头则会包含内容类型、长度、编码等信息。

常见的响应头字段有:

Content-Type:响应内容的MIME类型,例如 text/html、application/json。

Content-Length:响应内容的字节长度。

Server:服务器信息。

Set-Cookie:设置客户端的Cookie。

示例:

Content-Type: text/html; charset=UTF-8
Content-Length: 3495
Server: Apache/2.4.41 (Ubuntu)

响应体

响应体包含实际的数据内容,具体形式取决于响应的类型和请求内容。例如:HTML页面内容,JSON数据,文件的二进制数据等。

如果是状态码为204 No Content或 304 Not Modified的响应,则通常没有正文。

注意:响应体和响应头之间会添加一个空行来分隔内容。

7 Web页面的基本构成

HTML(超文本标记语言)

、、。

作用:定义网页的结构和内容。

内容:

结构标签:如

内容标签:如

、、。

表单标签:如 、、。

CSS(层叠样式表)

作用:控制网页的样式和布局。

内容

字体设置:如 font-family、font-size。

颜色设置:如 color、background-color。

布局设计:如 margin、padding、display、flex。

响应式设计:如媒体查询(@media)。

JavaScript(脚本语言)

作用:增加网页的交互性和动态功能。

应用

表单验证。

动画效果。

与服务器交互(如通过 AJAX请求)。

处理用户事件(如点击、悬停)。

Meta信息

中。

作用:提供页面的元数据,通常包含在

内容:

网页标题:

字符集:。

SEO信息:如 。

设备适配:如 。

示例:

< !DOCTYPE html >
< html lang="en" >
< head >
    < meta charset="UTF-8" >
    < meta name="viewport" content="width=device-width, initial-scale=1.0" >
    < title >Simple Page< /title >
    < style >
        body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }
        button { padding: 10px 20px; cursor: pointer; }
    < /style >
< /head >
< h1 >Hello, Web!< /h1 > < p >Click the button for a surprise.< /p > Click Me< /button > < /body > < /html >

8 Web页面交互

Web页面实现HTTP请求的方式:

HTTP请求页面

描述:客户端通过 HTTP协议向服务器发送请求,服务器处理后返回响应。

特点

最基础的交互方式。

包括常见的 HTTP方法:GET、POST、PUT、DELETE等。

示例

GET请求:浏览器访问网页,获取静态资源(HTML、CSS、JavaScript等)。

POST请求:提交表单数据。

表单提交

描述:通过 HTML表单向服务器提交数据。

特点

表单数据会被编码后随请求发送。

可使用 GET或 POST方法。

示例

< form action="/submit" method="post" >
    < input type="text" name="username" placeholder="Enter your name" >
    Submit< /button >
< /form >

AJAX(Asynchronous JavaScript and XML)

描述:使用 JavaScript在后台与服务器通信,更新部分页面内容而无需刷新整个页面。

特点

提高用户体验,减少页面加载时间。

现代开发中多用 JSON代替 XML。

示例

fetch('/api/data', {
    method: 'GET'
})
.then(response => response.json())
.then(data => console.log(data));

Web服务器响应处理

直接响应

定义:服务器直接处理请求,返回静态资源或简单的动态内容,而不调用外部脚本或程序。

特点

高效:直接处理请求,无需额外调用外部程序,适合静态内容。

适用场景

静态资源(HTML、CSS、JavaScript、图像等)的分发。

轻量级动态内容生成。

工作流程

客户端发送 HTTP请求。

服务器解析请求 URL,查找相应的资源(如文件路径)。

直接读取资源内容并返回给客户端,附加适当的 HTTP响应头。

CGI响应

定义:服务器通过 CGI(Common Gateway Interface)调用外部程序或脚本,处理客户端请求并生成动态响应内容。

特点

灵活性:可以动态生成内容,支持复杂逻辑。

适用场景

动态内容生成(如用户登录、数据查询)。

与数据库交互或其他后台服务的复杂逻辑处理。

工作流程

客户端发送 HTTP请求。

服务器解析请求并将请求数据(如 URL参数或表单数据)传递给 CGI程序。

CGI程序处理请求,生成响应内容并返回给服务器。

服务器将 CGI程序生成的内容包装为 HTTP响应发送给客户端。

9实现过程

接下来,我们看看如何通过浏览器修改W55MH32的网络配置。

注意:测试实例需要PC端和W55MH32处于同一网段。

首先需要编写网页内容,这里我们写了一个网页配置页面的内容以及提交后等待重启页面的内容,如下所示:

#define index_page "< html >n"                                                                                                                                                                            
"< head >n"                                                                                                                                                                            
"    < title >W55MH32 Configuration Page< /title >n"                                                                                                                                     
"    < style >n"                                                                                                                                                                       
"        body { font-family: Arial, sans-serif; margin: 20px; padding: 20px; background-color: #f4f4f9; }n"                                                                          
"        h1 { text-align: center; color: #333; }n"                                                                                                                                   
"        form { max-width: 400px; margin: auto; background: #ffffff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }n"                                 
"        label { display: block; margin-bottom: 8px; font-weight: bold; }n"                                                                                                          
"        input[type=text], input[type=submit] { width: 400px; padding: 8px; margin-bottom: 12px; border: 1px solid #ccc; border-radius: 4px; }n"                                     
"        input[type=submit] { background-color: #4CAF50; color: white; border: none; cursor: pointer; }n"                                                                            
"        input[type=submit]:hover { background-color: #45a049; }n"                                                                                                                   
"        input[readonly] { background-color: #e9ecef; color: #6c757d; border: 1px solid #ced4da; cursor: not-allowed; }n"                                                            
"        .error { color: red; font-size: 12px; margin-top: -10px; margin-bottom: 10px; }n"                                                                                           
"        input::placeholder { color: #aaa; font-style: italic; }n"                                                                                                                   
"    < /style >n"                                                                                                                                                                      
"    < script >n"                                                                                                                                                                      
"        function validateForm(event) {n"                                                                                                                                            
"            const ipPattern = /^(\d{1,3}\.){3}\d{1,3}$/;n"                                                                                                                       
"            let isValid = true;n"                                                                                                                                                   
"            document.querySelectorAll('.error').forEach(e => e.textContent = '');n"                                                                                                 
"            const fields = ['ip', 'subnet', 'gateway', 'dns'];n"                                                                                                                    
"            fields.forEach(field => {n"                                                                                                                                             
"                const input = document.forms[0][field];n"                                                                                                                           
"                if (input.value.trim() === '') {n"                                                                                                                                  
"                    input.placeholder = 'e.g., 192.168.1.1';n"                                                                                                                      
"                    document.getElementById(field + '-error').textContent = 'This field is required.';n"                                                                            
"                    isValid = false;n"                                                                                                                                              
"                } else if (!ipPattern.test(input.value)) {n"                                                                                                                        
"                    document.getElementById(field + '-error').textContent = 'Invalid IP address format.';n"                                                                         
"                    isValid = false;n"                                                                                                                                              
"                }n"                                                                                                                                                                 
"            });n"                                                                                                                                                                   
"            if (!isValid) {n"                                                                                                                                                       
"                event.preventDefault();n"                                                                                                                                           
"            }n"                                                                                                                                                                     
"        }n"                                                                                                                                                                         
"    < /script >n"                                                                                                                                                                     
"< /head >n"                                                                                                                                                                           
"
n" " < h1 >W55MH32 Configuration Page< /h1 >n" " < form method="post" action="config.cgi" onsubmit="validateForm(event)" >n" " < label >MAC Address: < /label >< input type="text" value="%s" readonly > n" " < label >IP Address: < /label >< input type="text" name="ip" placeholder="e.g., 192.168.1.1" value="%s" >

n" " < label >Subnet Mask: < /label >< input type="text" name="subnet" placeholder="e.g., 255.255.255.0" value="%s" >

n" " < label >Default Gateway: < /label >< input type="text" name="gateway" placeholder="e.g., 192.168.1.1" value="%s" >

n" " < label >DNS Server: < /label >< input type="text" name="dns" placeholder="e.g., 8.8.8.8" value="%s" >

n" " < input type="submit" value="Submit" >n" " < /form >n" "< /body >n" "< /html >n"

这里,我们提交网络地址信息的方式为POST,提交的地址为config.cgi:

#define CONFIG_SUCCESS_PAGE                                                                               
"< !DOCTYPE html >n"                                                                                   
"< html lang="en" >n"                                                                                
"< head >n"                                                                                            
"    < meta charset="UTF-8" >n"                                                                      
"    < meta name="viewport" content="width=device-width, initial-scale=1.0" >n"                    
"    < title >Configuration Modification Succeeded< /title >n"                                           
"    < style >n"                                                                                       
"        body {n"                                                                                    
"            font-family: Arial, sans-serif;n"                                                       
"            text-align: center;n"                                                                   
"            padding-top: 100px;n"                                                                   
"            background-color: #f0f0f0; n"                                                           
"        }n"                                                                                         
"        h1 {n"                                                                                      
"            color: green;n"                                                                         
"            animation: fadeInOut 2s infinite;n"                                                     
"        }n"                                                                                         
"        #countdown {n"                                                                              
"            font-size: 24px;n"                                                                      
"            margin-top: 20px;n"                                                                     
"            opacity: 0; n"                                                                          
"            animation: fadeIn 1s forwards;n"                                                        
"            animation-delay: 1s; n"                                                                 
"        }n"                                                                                         
"        @keyframes fadeIn {n"                                                                       
"            from {n"                                                                                
"                opacity: 0;n"                                                                       
"            }n"                                                                                     
"            to {n"                                                                                  
"                opacity: 1;n"                                                                       
"            }n"                                                                                     
"        }n"                                                                                         
"    < /style >n"                                                                                      
"< /head >n"                                                                                           
"
n" " < h1 >Configuration Modification Succeeded!< /h1 >n" " < p id="countdown" >Will redirect in 10 seconds. Please wait...< /p >n" "< script >n" " let seconds = 10;n" " const countdownElement = document.getElementById('countdown');n" " const countdownInterval = setInterval(() => {n" " seconds--;n" " countdownElement.textContent = `Will redirect in ${seconds} seconds. Please wait...`;n" " if (seconds === 0) {n" " clearInterval(countdownInterval);n" " window.location.href = 'http://%d.%d.%d.%d/';n" " }n" " }, 1000);n" "< /script >n" "< /body >n" "< /html >"

步骤一:从EEPROM中读取网络地址信息并配置

check_eeprom_network_info(&default_net_info);
network_init(ethernet_buf, &default_net_info); 

check_eeprom_network_info()函数的作用是检查EEPROM中是否有网络地址信息,如果有则赋值给default_net_info结构体。函数内容如下:

uint8_t check_eeprom_network_info(wiz_NetInfo *net_info)
{
 wiz_NetInfo eeprom_net_info = {0};
 /*-----------------------------------------------------------------------------------*/
 if (ee_CheckDevice(EEPROM_DEV_ADDR) == 1)
 {
     /* No EEPROM detected */
     printf("No serial EEPROM detected!rn");
     return 0;
 }
 ee_ReadBytes((uint8_t *)&eeprom_net_info, 0, sizeof(eeprom_net_info));
 if (eeprom_net_info.mac[0] == 0x00 && eeprom_net_info.mac[1] == 0x08 && eeprom_net_info.mac[2] == 0xdc)
 {
     memcpy(net_info, &eeprom_net_info, sizeof(wiz_NetInfo));
     return 1;
 }
 return 0;
}

步骤二:注册网页内容及HTTP Server初始化

printf("Please enter% d.% d.% d.% d in your browser to access the %s HTTP serverrn", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3], _WIZCHIP_ID_);
sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", net_info.mac[0], net_info.mac[1], net_info.mac[2], net_info.mac[3], net_info.mac[4], net_info.mac[5]);
sprintf(ip, "%d.%d.%d.%d", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3]);
sprintf(sn, "%d.%d.%d.%d", net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3]);
sprintf(gw, "%d.%d.%d.%d", net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]);
sprintf(dns, "%d.%d.%d.%d", net_info.dns[0], net_info.dns[1], net_info.dns[2], net_info.dns[3]);
sprintf(page, (char *)index_page, mac, ip, sn, gw, dns);
reg_httpServer_webContent((uint8_t *)"index.html", (uint8_t *)page);         // Build HTTP server web pages
httpServer_init(http_tx_ethernet_buf, http_rx_ethernet_buf, 1, socknumlist); // Initializing the HTTP server

reg_httpServer_webContent()函数的作用是注册web内容,这里可以是页面,也可以是JavaScript代码。

httpServer_init的作用是初始化HTTP Server参数,四个参数分别是HTTP发送缓存、HTTP接收缓存、使用的SOCKET数量以及对应的SOCKET列表。

步骤三:注册HTTP超时中断程序

/**
* @brief   1ms timer IRQ Handler
* @param   none
* @return  none
*/
void TIM3_IRQHandler(void)
{
 static uint32_t tim3_1ms_count = 0;
 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
 {
     tim3_1ms_count++;
     if (tim3_1ms_count >= 1000)
     {
         DHCP_time_handler();
         httpServer_time_handler();
         tim3_1ms_count = 0;
     }
     TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
 }
}

步骤四:运行HTTP Server程序

while (1)
{
   httpServer_run(SOCKET_ID);
}

httpServer_run()函数的逻辑跟TCP Server基本一致,也是运行了一个状态机,根据SOCKET不同状态,执行相应的HTTP Server部分的处理,内容如下:

void httpServer_run(uint8_t seqnum)
{
 uint8_t  s; // socket number
 uint16_t len;
 uint32_t gettime = 0;
#ifdef _HTTPSERVER_DEBUG_
 uint8_t destip[4] = {
     0,
 };
 uint16_t destport = 0;
#endif
 http_request        = (st_http_request *)pHTTP_RX; // Structure of HTTP Request
 parsed_http_request = (st_http_request *)pHTTP_TX;
 // Get the H/W socket number
 s = getHTTPSocketNum(seqnum);
 /* HTTP Service Start */
 switch (getSn_SR(s))
 {
 case SOCK_ESTABLISHED:
     // Interrupt clear
     if (getSn_IR(s) & Sn_IR_CON)
     {
         setSn_IR(s, Sn_IR_CON);
     }
     // HTTP Process states
     switch (HTTPSock_Status[seqnum].sock_status)
     {
     case STATE_HTTP_IDLE:
         if ((len = getSn_RX_RSR(s)) > 0)
         {
             if (len > DATA_BUF_SIZE) len = DATA_BUF_SIZE;
             len = recv(s, (uint8_t *)http_request, len);
             *(((uint8_t *)http_request) + len) = '';
             parse_http_request(parsed_http_request, (uint8_t *)http_request);
#ifdef _HTTPSERVER_DEBUG_
             getSn_DIPR(s, destip);
             destport = getSn_DPORT(s);
             printf("rn");
             printf("> HTTPSocket[%d] : HTTP Request received ", s);
             printf("from %d.%d.%d.%d : %drn", destip[0], destip[1], destip[2], destip[3], destport);
#endif
#ifdef _HTTPSERVER_DEBUG_
             printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONErn", s);
#endif
             // HTTP 'response' handler; includes send_http_response_header / body function
             http_process_handler(s, parsed_http_request);
             gettime = get_httpServer_timecount();
             // Check the TX socket buffer for End of HTTP response sends
             while (getSn_TX_FSR(s) != (getSn_TxMAX(s)))
             {
                 if ((get_httpServer_timecount() - gettime) > 3)
                 {
#ifdef _HTTPSERVER_DEBUG_
                     printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE: TX Buffer clear timeoutrn", s);
#endif
                     break;
                 }
             }
             if (HTTPSock_Status[seqnum].file_len > 0)
                 HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC;
             else
                 HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; // Send the 'HTTP response' end
         }
         break;
     case STATE_HTTP_RES_INPROC:
         /* Repeat: Send the remain parts of HTTP responses */
#ifdef _HTTPSERVER_DEBUG_
         printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_INPROCrn", s);
#endif
         // Repeatedly send remaining data to client
         send_http_response_body(s, 0, http_response, 0, 0);
         if (HTTPSock_Status[seqnum].file_len == 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE;
         break;
     case STATE_HTTP_RES_DONE:
#ifdef _HTTPSERVER_DEBUG_
         printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_DONErn", s);
#endif
         // Socket file info structure re-initialize
         HTTPSock_Status[seqnum].file_len    = 0;
         HTTPSock_Status[seqnum].file_offset = 0;
         HTTPSock_Status[seqnum].file_start  = 0;
         HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE;
//#ifdef _USE_SDCARD_
//     f_close(&fs);
//#endif
#ifdef _USE_WATCHDOG_
         HTTPServer_WDT_Reset();
#endif
         http_disconnect(s);
         break;
     default:
         break;
     }
     break;
 case SOCK_CLOSE_WAIT:
#ifdef _HTTPSERVER_DEBUG_
     printf("> HTTPSocket[%d] : ClOSE_WAITrn", s); // if a peer requests to close the current connection
#endif
     disconnect(s);
     break;
 case SOCK_CLOSED:
     if (reboot_flag)
     {
         NVIC_SystemReset();
     }
#ifdef _HTTPSERVER_DEBUG_
     printf("> HTTPSocket[%d] : CLOSEDrn", s);
#endif
     if (socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */
     {
#ifdef _HTTPSERVER_DEBUG_
         printf("> HTTPSocket[%d] : OPENrn", s);
#endif
     }
     break;
 case SOCK_INIT:
     listen(s);
     break;
 case SOCK_LISTEN:
     break;
 default:
     break;
 } // end of switch
#ifdef _USE_WATCHDOG_
 HTTPServer_WDT_Reset();
#endif
}

步骤五:请求内容处理

POST方式的CGI请求处理,在httpUtil.c文件的predefined_set_cgi_processor()函数中处理。

GET方式的CGI请求处理,在httpUtil.c文件的predefined_get_cgi_processor()函数中处理。

 uint8_t predefined_set_cgi_processor(uint8_t *uri_name, uint8_t *uri, uint8_t *buf, uint16_t *len)
{
 if (strcmp((const char *)uri_name, "config.cgi") == 0)
 {
     uint8_t    *param;
     wiz_NetInfo new_net_info = {0};
     wizchip_getnetinfo(&new_net_info);
     param = get_http_param_value((char *)uri, "ip");        //获取IP地址
     parse_ip((char *)param, new_net_info.ip);               //更新IP地址
     param = get_http_param_value((char *)uri, "subnet");    //获取子网掩码
     parse_ip((char *)param, new_net_info.sn);               //更新子网掩码
     param = get_http_param_value((char *)uri, "gateway");   //获取默认网关
     parse_ip((char *)param, new_net_info.gw);               //更新默认网关
     param = get_http_param_value((char *)uri, "dns");       //获取DNS地址
     parse_ip((char *)param, new_net_info.dns);              //更新DNS地址

步骤六:重启设备

在httpServer_run()函数中,当SOCKET处于SOCK_CLOSED状态时(即上次请求已经处理完毕),再进行复位操作,避免出现客户端请求后,W55MH32未响应就重启导致客户端请求超时的情况。

case SOCK_CLOSED:
if (reboot_flag)
{
   NVIC_SystemReset();
}

10运行结果

烧录例程运行后,首先进行了PHY链路检测,然后是通过DHCP获取网络地址并打印网络地址信息,最后HTTP Server程序开始监听客户端的请求并处理响应,如下图所示:

wKgZO2iBjJCABr5DAACulOuqzP0718.png

接着我们打开浏览器,输入W55MH32的IP地址进行访问。

wKgZPGiBjJCAJX8DAABJ9nP3VP4358.png

然后我们将IP地址改为192.168.1.33,DNS服务器地址改为114.114.114.114,并点击Submit按钮。

等待W55MH32重启后,浏览器会自动跳转至新地址。

wKgZO2iBjJCAVvesAABJ9nP3VP4684.png

11总结

本文介绍了在 W55MH32芯片上实现 HTTP Server功能,并通过浏览器修改其网络地址信息的方法。阐述了 HTTP协议的概念、特点、应用场景、工作流程、请求方法、响应内容,以及 Web页面构成和交互方式。展示了在W55MH32上实现的过程。

下一篇将讲解在该芯片上实现 SNTP授时功能,介绍从 SNTP服务器获取准确时间的原理和实现步骤。敬请期待!

WIZnet是一家无晶圆厂半导体公司,成立于 1998年。产品包括互联网处理器 iMCU™,它采用 TOE(TCP/IP卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU™面向各种应用中的嵌入式互联网设备。

WIZnet在全球拥有 70多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。

香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。


审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5182

    文章

    20094

    浏览量

    327491
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    第三十 W55MH32 HTTP_Server&amp;NetBIOS示例

    本文讲解了如何在 W55MH32 芯片上实现 HTTP_Server 与 NetBIOS 功能,并通过 NetBIOS 访问 HTTP 服务器网页内容,通过实战例程展示了在主循环中并行处理 H
    的头像 发表于 07-24 16:21 772次阅读
    第三十<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> <b class='flag-5'>HTTP_Server</b>&amp;NetBIOS<b class='flag-5'>示例</b>

    第二十九章 W55MH32 Modbus_TCP_Server示例

    本文讲解了如何在 W55MH32 芯片上实现 Modbus TCP 协议的服务器模式,通过实战例程展示了从初始化 LED 相关函数、主循环调用处理函数到解析处理接收到的报文的完整过程。文章详细介绍了
    的头像 发表于 07-24 16:18 473次阅读
    第二十<b class='flag-5'>九章</b> <b class='flag-5'>W55MH32</b> Modbus_TCP_<b class='flag-5'>Server</b><b class='flag-5'>示例</b>

    第二十六章 W55MH32 上位机搜索和配置示例

    本文讲解了如何在 W55MH32 芯片上实现上位机搜索和配置功能,通过实战例程展示了使用开源上位机配置工具 SmartConfigTool 搜索局域网中的 W55MH32 并进行网络地址配置的过程
    的头像 发表于 07-24 16:13 525次阅读
    第二十六章 <b class='flag-5'>W55MH32</b> 上位机搜索和配置<b class='flag-5'>示例</b>

    第十八章 W55MH32 FTP_Server示例

    本文讲解了如何在 W55MH32 芯片上实现 FTP 协议的服务器模式,通过实战例程展示了使用 W55MH32 作为 FTP 服务器与 PC 端进行文件传输、目录操作等功能的过程,涵盖获取网络配置
    的头像 发表于 07-24 11:55 399次阅读
    第十八章 <b class='flag-5'>W55MH32</b> FTP_<b class='flag-5'>Server</b><b class='flag-5'>示例</b>

    第十七 W55MH32 ARP示例

    文讲解了如何在 W55MH32 芯片上通过 MAC RAW 模式实现 ARP 协议,将 IP 地址解析为 MAC 地址,通过实战例程展示了从发送 ARP 请求到接收并处理响应的完整过程。文章详细介绍
    的头像 发表于 07-24 11:49 533次阅读
    第十七<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> ARP<b class='flag-5'>示例</b>

    第十六章 W55MH32 PING示例

    本文讲解了如何在 W55MH32 芯片上通过 IPRAW 模式实现 ICMP 协议中的 PING 命令,以进行网络连通性测试,通过实战例程展示了从发送 PING 请求、接收并解析回复到统计结果的完整
    的头像 发表于 07-24 11:41 449次阅读
    第十六章 <b class='flag-5'>W55MH32</b> PING<b class='flag-5'>示例</b>

    第十五 W55MH32 SNMP示例

    本文讲解了如何在 W55MH32 芯片上实现 SNMP 功能,通过实战例程展示了使用 MIB Browser 管理 W55MH32 的具体过程,涵盖在 MIB Browser 中创建分支、添加叶子
    的头像 发表于 07-24 10:43 623次阅读
    第十五<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> SNMP<b class='flag-5'>示例</b>

    第十四章 W55MH32 TFTP示例

    本文讲解了如何在 W55MH32 芯片上实现 TFTP 协议,通过实战例程详细展示了使用 TFTP 客户端模式从服务器获取文本文件的过程,涵盖 TFTP 初始化、发送读请求、运行协议并处理结果等核心
    的头像 发表于 07-24 10:37 558次阅读
    第十四章 <b class='flag-5'>W55MH32</b> TFTP<b class='flag-5'>示例</b>

    第十二 W55MH32 NetBIOS示例

    本文讲解了如何在 W55MH32 芯片上实现 NetBIOS 功能,通过实战例程展示了利用 NetBIOS 进行名称 PING 测试的具体过程,包括 NetBIOS 功能的调用、请求处理、名称解析
    的头像 发表于 07-24 09:58 510次阅读
    第十二<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> NetBIOS<b class='flag-5'>示例</b>

    第十 W55MH32 SNTP示例

    本文讲解了如何在W55MH32芯片上实现SNTP授时功能,通过实例详细展示了从SNTP服务器同步时间的实现流程,包括时间请求、响应解析和本地时间校准等核心步骤。文章还对SNTP的应用场景进行了分析,帮助读者理解其在时间同步中的实际应用价值。
    的头像 发表于 07-24 09:43 740次阅读
    第十<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> SNTP<b class='flag-5'>示例</b>

    第六 W55MH32 UDP Multicast示例

    本文介绍了在W55MH32芯片上实现UDP组播的原理、应用场景及回环测试方法,并通过实战代码展示了其具体实现过程。下一篇文章将聚焦DNS例程,讲解其工作原理及实现方法,帮助大家更深入地理解网络通信。敬请期待!
    的头像 发表于 07-24 09:19 573次阅读
    第六<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> UDP Multicast<b class='flag-5'>示例</b>

    第五 W55MH32 UDP示例

    本文介绍了在 W55MH32 芯片上实现 UDP 通信及数据回环测试的方法。阐述了 UDP 协议的概念、特点、应用场景、报文传输流程和报文结构,展示了实现过程,借助网络调试工具完成测试。
    的头像 发表于 07-24 09:13 556次阅读
    第五<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> UDP<b class='flag-5'>示例</b>

    第三 W55MH32 TCP Client示例

    本文介绍在 W55MH32 芯片上实现 TCP 客户端模式进行数据回环测试的方法。阐述 TCP 协议概念、特点、与 UDP 区别、应用场景及相关机制。展示实现过程,包括开启 Keepalive 功能,在主循环运行测试程序。烧录例程后进行 PHY 链路检测、获取网络地址,再借助网络调试工具测试。
    的头像 发表于 07-24 09:06 677次阅读
    第三<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> TCP Client<b class='flag-5'>示例</b>

    第二 W55MH32 DHCP示例

    本文介绍 DHCP 协议,包括其在 IP 网络自动分配参数的功能、便捷配置等特点、工作原理、报文格式和应用场景。通过 W55MH32 实战例程展示动态获取网络地址信息过程,含注册定时器中断、启用模式和获取信息等步骤,烧录后可完成检测与信息打印,PC 端能 PING 通设备。
    的头像 发表于 07-24 09:02 530次阅读
    第二<b class='flag-5'>章</b> <b class='flag-5'>W55MH32</b> DHCP<b class='flag-5'>示例</b>

    W55MH32高性能以太网单片机教程 第九章 窗口看门狗(WWDG)

    本章介绍了W55MH32的窗口看门狗(WWDG),其用于监测软件故障,具可编程递减计数器等特性。从寄存器、中断喂狗和复位测试两个程序例程进行讲解。
    的头像 发表于 05-27 10:26 653次阅读
    <b class='flag-5'>W55MH32</b>高性能以太网单片机教程 <b class='flag-5'>第九章</b> 窗口看门狗(WWDG)