W5500 充当http server - web服务器的实现

笔者通过w5500实现web服务器点灯

1.http协议概述

HTTP是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。

2.http服务器实验设计

笔者用 W5500 建立自己的网页服务器,你只在浏览器地址栏里键入W5500 IP 地址,就成功在你的网页上显示出来了。 HTTP Server 实现原理图如下:

3.程序设计

3.1 w5500初始化

        分别对w5500进行ip地址的设定、和我们单片机进行spi通信的配置。我们在w5500_conf.c文件中配置好ip地址、子网掩码、网关。要保证ip地址和网关在同一个网段内才能正常通信。再者配置好我们的spi引脚与w5500模块的连接即可完成通信。而

3.2 http server回环测试函数(附解析)

void do_https(void)
{
	uint8 ch=SOCK_HTTPS;																		/*定义一个socket*/
	uint16 len;
	
	st_http_request *http_request;													/*定义一个结构指针*/
	memset(rx_buf,0x00,MAX_URI_SIZE);
	http_request = (st_http_request*)rx_buf;					 
	/* http service start */
	switch(getSn_SR(ch))																		/*获取socket状态*/
	{
		case SOCK_INIT:																				/*socket处于初始化状态*/
			listen(ch);
			break;
		
		case SOCK_LISTEN:																			/*socket处于监听状态*/
			break;
		
		case SOCK_ESTABLISHED:																/*socket处于连接状态*/
			if(getSn_IR(ch) & Sn_IR_CON)
			{
				setSn_IR(ch, Sn_IR_CON);													/*清除中断标志位*/
			}
			if ((len = getSn_RX_RSR(ch)) > 0)		
			{
				len = recv(ch, (uint8*)http_request, len); 				/*接收http请求*/
				*(((uint8*)http_request)+len) = 0;
				proc_http(ch, (uint8*)http_request);							/*接收http请求并发送http响应*/
				disconnect(ch);
			}
			break;
			
		case SOCK_CLOSE_WAIT:   															/*socket处于等待关闭状态*/
			if ((len = getSn_RX_RSR(ch)) > 0)
			{
				len = recv(ch, (uint8*)http_request, len);				/*接收http请求*/      
				*(((uint8*)http_request)+len) = 0;
				proc_http(ch, (uint8*)http_request);							/*接收http请求并发送http响应*/
			}
			disconnect(ch);
			break;
			
		case SOCK_CLOSED:                   									/*socket处于关闭状态*/
			socket(ch, Sn_MR_TCP, 80, 0x00);   									/*打开socket*/
			break;
		
		default:
			break;
	}
}

程序解读1:在这里声明一下,调用 do_http() 函数实现 HTTP 服务器,此函数只执行一次,除了reboot_flag==1会重启再重新执行此函数。

/**
*@brief		接收http请求报文并发送http响应,以下这段代码很重要,是http响应阶段
*@param		s: http服务器socket
*@param		buf:解析报文内容
*@return	无
*/
void proc_http(SOCKET s, uint8 * buf)
{
	int8* name; 											
	int8 req_name[32]={0x00,};															/*定义一个http响应报文的指针*/
	unsigned long file_len=0;																/*定义http请求报文头的结构体指针*/
	uint16 send_len=0;
	uint8* http_response;
	st_http_request *http_request;
	memset(tx_buf,0x00,MAX_URI_SIZE);
	http_response = (uint8*)rx_buf;
	http_request = (st_http_request*)tx_buf;
	parse_http_request(http_request, buf);    							/*解析http请求报文头*/

	switch (http_request->METHOD)		
  {
		case METHOD_ERR :																			/*请求报文头错误*/
			memcpy(http_response, ERROR_REQUEST_PAGE, sizeof(ERROR_REQUEST_PAGE));
			send(s, (uint8 *)http_response, strlen((int8 const*)http_response));
			break;
		
		case METHOD_HEAD:																			/*HEAD请求方式*/
			
		case METHOD_GET:																			/*GET请求方式*/
			name = http_request->URI;
			if(strcmp(name,"/index.htm")==0 || strcmp(name,"/")==0 || (strcmp(name,"/index.html")==0))
			{
				file_len = strlen(INDEX_HTML);
				make_http_response_head((uint8*)http_response, PTYPE_HTML,file_len);
				send(s,http_response,strlen((char const*)http_response));
				send_len=0;
				while(file_len)
				{
					if(file_len>1024)
					{
						if(getSn_SR(s)!=SOCK_ESTABLISHED)
						{
							return;
						}
						send(s, (uint8 *)INDEX_HTML+send_len, 1024);
						send_len+=1024;
						file_len-=1024;
					}
					else
					{
						send(s, (uint8 *)INDEX_HTML+send_len, file_len);
						send_len+=file_len;
						file_len-=file_len;
					} 
				}
			}
			else if(strcmp(name,"/w5500.js")==0)
			{
				memset(tx_buf,0,MAX_URI_SIZE);
				make_basic_config_setting_json_callback(tx_buf,CONTROLH);
				sprintf((char *)http_response,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length:%d\r\n\r\n%s",strlen(tx_buf),tx_buf);
				send(s, (u_char *)http_response, strlen((char const*)http_response));
			}
			break;
			
		case METHOD_POST:																			/*POST请求*/
			mid(http_request->URI, "/", " ", req_name);					/*获取该请求的文件名*/
			if(strcmp(req_name,"config.cgi")==0)							  	
			{
				cgi_ipconfig(http_request);												/*将配置信息写进单片机eeprom*/
				make_cgi_response(5,(int8*)ConfigMsg.lip,tx_buf);	/*生成响应的文本部分*/        
				sprintf((char *)http_response,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length:%d\r\n\r\n%s",strlen(tx_buf),tx_buf);
																													/*发送http响应*/
				send(s, (u_char *)http_response, strlen((char *)http_response));		
				disconnect(s);																		/*断开socket连接*/				
				reboot_flag=1;																		/*重启标志位置1*/
				return;
			}
			break;
			
		default :
			break;
	}
}
/**
*@brief		功能函数,可以配置读取到的值以驱动单片机
*@param		http_request:定义一个http请求的结构体指针
*@return	无
*/
void cgi_ipconfig(st_http_request *http_request)
{ 
 
  uint8 * param;
  param = get_http_param_value(http_request->URI,"room");		/*房间号,其实笔者是点亮LED1,读者可以对代码进行优化*/
  if(param)
  {
    LED1_ON;	
  }
  param = get_http_param_value(http_request->URI,"leftroom");		/*获取需要关灯的房号,笔者没配置,读者可优化*/
  if(param)
  {

  }
  param = get_http_param_value(http_request->URI,"a");	/*获取修改后的a,这里我没配置*/
  if(param)
  {
	
  }					
}
/*以下是笔者设计的网页*/
#ifndef __WEBPAGE_H
#define __WEBPAGE_H
#define INDEX_HTML  "<!DOCTYPE html>"\
"<html>"\
"<head>"\
"<title>室内各电器配置—小兵科技</title>"\
"<meta http-equiv='Content-Type' content='text/html; charset=GB2312'/>"\
"<style type='text/css'>"\
"body {text-align:left; background-color:#c0deed;font-family:Verdana;}"\
"#main {margin-right:auto;margin-left:auto;margin-top:30px;}"\
"label{display:inline-block;width:150px;}"\
"#main h3{color:#66b3ff; text-decoration:underline;}"\
"</style>"\
"<script>"\
"function $(id) { return document.getElementById(id); };"\
"function settingsCallback(o) {"\
"if ($('txtPub')) $('txtPub').value = 100;"\
"if ($('txtRoom')) $('txtRoom').value = o.room;"\
"if ($('txtLeftroom')) $('txtLeftroom').value = o.ip;"\
"if ($('txtA')) $('txt').value = o.sub;"\
"if ($('txtB')) $('txtB').value = o.gw;"\
"};"\
"</script>"\
"</head>"\
"<body>"\
"<div id='main'>"\
"<div style='background:snow; display:block;padding:10px 20px;'>"\
"<h3>小彬科技智能家居</h3>"\
"<form id='frmSetting' method='POST' action='config.cgi'>"\
"<p><label for='txtPub'>版本号:</label><input type='text' id='txtPub' name='pub' size='16' disabled='disabled' /></p>"\
"<p><label for='txtRoom'>点亮的灯(输入1到7房间号):</label><input type='text' id='txtRoom' name='room' size='16' /></p>"\
"<p><label for='txtLeftroom'>关掉哪个灯(输入1到7房间号):</label><input type='text' id='txtLeftroom' name='leftroom' size='16' /></p>"\
"<p><label for='txtA'>未开发功能:</label><input type='text' id='txtA' name='a' size='16' /></p>"\
"<p><label for='txtB'>未开放功能:</label><input type='text' id='txtB' name='b' size='16' /></p>"\
"<p><input type='submit' value='确认并执行' /></p>"\
"</form>"\
"</div>"\
"</div>"\
"<div style='margin:5px 5px;'>"\
"&copy;Copyright 2021 by 清风芝明"\
"</div>"\
"<script type='text/javascript' src='w5500.js'></script>"\
"</body>"\
"</html>"

#endif

3.3主函数

#include <stdio.h>
#include <string.h>
#include "stm32f10x.h"
#include "bsp_usart1.h"
#include "bsp_i2c_ee.h"
#include "bsp_i2c_gpio.h"
#include "bsp_led.h"

#include "w5500.h"
#include "W5500_conf.h"
#include "socket.h"
#include "utility.h"

/*app函数头文件*/
#include "http_server.h"
#include "httputil.h"

uint8 reboot_flag = 0;
int main(void)
{     
    
    systick_init(72);                                        /*初始化Systick工作时钟*/
    USART1_Config();                                        /*初始化串口通信:115200@8-n-1*/
    i2c_CfgGpio();                                            /*初始化eeprom*/
    LED_GPIO_Config();              //笔者点灯,所以初始化,读者想增加更多功能也可增加初始化...
    printf("  网络初始化 Demo V1.0 \r\n");        

    gpio_for_w5500_config();                                /*初始化MCU相关引脚*/
    reset_w5500();                                            /*硬复位W5500*/
    set_w5500_mac();                                        /*配置MAC地址*/
    set_w5500_ip();                                            /*配置IP地址*/
    
    socket_buf_init(txsize, rxsize);        /*初始化8个Socket的发送接收缓存大小*/
    
    printf(" 应用程序执行中…… \r\n"); 
    printf(" 在IE浏览器中输入 W5500的IP就可访问web Server \r\n");
  
    while(1)                                                         /*循环执行的函数*/ 
    {
    do_https();/*Web server测试程序*/
//    if(reboot_flag==1)
//   reboot();
    }

4.成果演示

 在点亮的灯处输入1

 点击确认并执行之后的现象

 笔者的代码应该还有更多值得优化的地方,这应该也算是一个应用,不过存在一些缺陷,点完灯之后需要手动去复位开发板以熄灭灯等等,可以后续进行优化。通过编写网页也更加深刻理解http的响应机制,也是具有不错的收获,读者也可以试着自己改写一个网页。

  • 6
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈俊帆Linux_Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值