diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index ee75fe950..6c38cba7d 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -126,7 +126,7 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y) endif ifeq ($(CONFIG_USER_TEST_WEBSERVER),y) - SRC_FILES += + SRC_FILES += test_webserver/test_webserver.c endif ifeq ($(CONFIG_USER_TEST_MQTTCLIENT),y) diff --git a/APP_Framework/Applications/app_test/test_webserver/README.md b/APP_Framework/Applications/app_test/test_webserver/README.md new file mode 100644 index 000000000..fe0461c4e --- /dev/null +++ b/APP_Framework/Applications/app_test/test_webserver/README.md @@ -0,0 +1,67 @@ +# 基于矽璓已实现的Lwip,在ARM上实现基本的Web服务## + +## 1. 简介 +基于矽璓已实现的Lwip,在ARM上实现基本的Web服务,其功能支持IP、GateWay、DNS、子网掩码等网络参数的设置。 +主要功能为:web服务等待Http请求的到来,解析Http报文后,设置本机的网络参数信息,在终端打印设置后的网络参数信息,并返回浏览器客户端成功响应。 + +## 2. 数据结构设计说明 +Server的网络结构参数为: +``` +struct ServerNet +{ + char local_ip[20]; + char local_mask[20]; + char local_gw[20]; + char local_dns[20]; +}ServerNet; +``` + +主要实现了以下几个函数: +``` +TcpThread: 建立socket监听,循环等待网络通信事件的到来; +HandleHttpRequest:处理并解析Http报文,得到网络参数信息; +AddrUpdate: 根据到来的参数,更新本机网络参数; +LwipShowIP:显示网络参数信息,包括IP、GateWay、DNS、子网掩码; +LwipSetIP: 设置网络参数信息,包括IP、GateWay、DNS、子网掩码; +ShowDns: 显示dns网址; +SetDns: 设置dns网址; +``` +除此之外,还包括两个工具函数: +``` +SubstractServerNet: 截取http报文的请求体,格式为:ip=192.168.1.9&netmask=255.255.255.0&iproute=192.168.1.1&dns=114.114.114.114 +substring: 截取字符串 + +``` + +## 3. 测试程序说明 +1. 通过数据线将开发板连接电脑,并通过网线连接使开发板接入家庭局域网。 +2. 将TestWebserver注册为shell 命令,编译前通过menuconfig打开lwip和TestWebserver功能。 +3. 将编译成功的XiZi-edu-arm32.bin文件烧录到arm板子。烧录bin文件前,需要将开发板boot引脚拉高(盖上跳帽),上电后再按下reset按键,之后可以点击烧写工具的执行按钮,等待烧写完成。 +4. 将boot引脚拉低(摘下跳帽),按下reset按键,使用串口工具显示xiuos的命令行界面。 +5. 将开发板的本机ip通过setip命令设置为与电脑端在同一个局域网之下,利用ping命令检测成功通信。 +6. 运行TestWebserver命令验证功能。 + +## 4. 运行结果(##需结合运行测试截图按步骤说明##) + + +烧录程序,boot引脚拉高,按下reset按键。 + + + +点击执行烧录,程序烧录成功。 + + + +打开串口调试工具,xiuos程序成功在开发板上运行。 + + + +利用setip命令,修改开发板ip,使得开发板和电脑在同一个局域网内,并使用ping命令测试。 + + + +在服务端运行TestWebserver命令,打开index.html,设置网络参数信息,点击提交,发送http请求。 + + + +web服务收到http请求后并打印post请求报文,以及修改后的开发板的网络参数信息,包括IP、子网掩码、GateWay和DNS。 diff --git a/APP_Framework/Applications/app_test/test_webserver/index.html b/APP_Framework/Applications/app_test/test_webserver/index.html new file mode 100644 index 000000000..d0514189a --- /dev/null +++ b/APP_Framework/Applications/app_test/test_webserver/index.html @@ -0,0 +1,33 @@ + + + + + 表单 + + + + +
+

设置路由信息

+ + +

IP地址:

+

子网掩码:

+

默认网关:

+

DNS服务器

+

+ + +

+ +
+ + + diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/1.png b/APP_Framework/Applications/app_test/test_webserver/photos/1.png new file mode 100644 index 000000000..2c3980afd Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/1.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/2.png b/APP_Framework/Applications/app_test/test_webserver/photos/2.png new file mode 100644 index 000000000..e2fc46ebd Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/2.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/3.png b/APP_Framework/Applications/app_test/test_webserver/photos/3.png new file mode 100644 index 000000000..0db94c2f8 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/3.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/4.png b/APP_Framework/Applications/app_test/test_webserver/photos/4.png new file mode 100644 index 000000000..7f337458a Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/4.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/5.png b/APP_Framework/Applications/app_test/test_webserver/photos/5.png new file mode 100644 index 000000000..85ab2f41e Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/5.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/photos/6.png b/APP_Framework/Applications/app_test/test_webserver/photos/6.png new file mode 100644 index 000000000..37b6e162f Binary files /dev/null and b/APP_Framework/Applications/app_test/test_webserver/photos/6.png differ diff --git a/APP_Framework/Applications/app_test/test_webserver/test_webserver.c b/APP_Framework/Applications/app_test/test_webserver/test_webserver.c new file mode 100644 index 000000000..a5f15f2c1 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_webserver/test_webserver.c @@ -0,0 +1,218 @@ +/** +* @file: test_webserver.c +* @brief: a application of test webserver function +* @version: 1.0 +* @author: Yao wenying +* @date: 2023/08/20 +*/ + + +#include +#include "test_webserver.h" + +/**设置ip,网关,子网掩码这部分参考lwip_config_demo.c*/ +void LwipShowIP() +{ + // find default netdev + lw_notice("\r\n************************************************\r\n"); + lw_notice(" Network Configuration\r\n"); + lw_notice("************************************************\r\n"); + lw_notice(" ETH0 IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_eth0_ipaddr)[0], ((u8_t*)&lwip_eth0_ipaddr)[1], + ((u8_t*)&lwip_eth0_ipaddr)[2], ((u8_t*)&lwip_eth0_ipaddr)[3]); + lw_notice(" ETH0 IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_eth0_netmask)[0], ((u8_t*)&lwip_eth0_netmask)[1], + ((u8_t*)&lwip_eth0_netmask)[2], ((u8_t*)&lwip_eth0_netmask)[3]); + lw_notice(" ETH0 IPv4 Gateway : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_gwaddr)[0], ((u8_t*)&lwip_eth0_gwaddr)[1], + ((u8_t*)&lwip_eth0_gwaddr)[2], ((u8_t*)&lwip_eth0_gwaddr)[3]); + lw_notice("************************************************\r\n"); +} + +uint8_t enet_idd = 0; +void LwipSetIP(int argc, char *argv[]) +{ + if(argc >= 4) + { + printf("lw: [%s] ip %s mask %s gw %s netport %s\n", __func__, argv[1], argv[2], argv[3], argv[4]); + sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]); + sscanf(argv[2], "%d.%d.%d.%d", &lwip_netmask[0], &lwip_netmask[1], &lwip_netmask[2], &lwip_netmask[3]); + sscanf(argv[3], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]); + sscanf(argv[4], "%d", &enet_idd); + + if(0 == enet_idd) + { + printf("save eth0 info\n"); + memcpy(lwip_eth0_ipaddr, lwip_ipaddr, 20); + memcpy(lwip_eth0_netmask, lwip_netmask, 20); + memcpy(lwip_eth0_gwaddr, lwip_gwaddr, 20); + } + else if(1 == enet_idd) + { + printf("save eth1 info\n"); + memcpy(lwip_eth1_ipaddr, lwip_ipaddr, 20); + memcpy(lwip_eth1_netmask, lwip_netmask, 20); + memcpy(lwip_eth1_gwaddr, lwip_gwaddr, 20); + } + } + else if(argc == 2) + { + printf("lw: [%s] set eth0 ipaddr %s \n", __func__, argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]); + memcpy(lwip_eth0_ipaddr, lwip_ipaddr, strlen(lwip_ipaddr)); + } + // sys_thread_new("SET ip address", LwipSetIPTask, &enet_id, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); + printf("lw: [%s] config netport id[%d]\n", __func__, enet_idd); + lwip_config_net(enet_idd, lwip_ipaddr, lwip_netmask, lwip_gwaddr); +} + +void ShowDns(){ + const ip_addr_t *dns = dns_getserver(0); + char *dns_ip = ipaddr_ntoa(dns); + printf("lw: eth0 dns is %s \n", dns_ip); +} + +void SetDns(char* ip){ + ip_addr_t dns; + ipaddr_aton(ip, &dns); + dns_setserver(0, &dns); + printf("ETH0 Set DNS Success!\n"); +} + +void AddrUpdate() +{ + char *argv[5]; + argv[1] = ServerNet.local_ip; + argv[2] = ServerNet.local_mask; + argv[3] = ServerNet.local_gw ; + argv[4] = 0; + LwipSetIP(4, argv); + LwipShowIP(); + SetDns(ServerNet.local_dns); + ShowDns(); +} + +char *substring(char *dst,char *src,int start,int len) +{ + char *p=dst; + char *q=src; + int length=strlen(src); + if(start>=length||start<0) + return NULL; + if(len>length) + len=length-start; + q+=start; + while(len--) + { + *(p++)=*(q++); + } + *(p++)='\0'; + return dst; +} + +void SubstractServerNet(char * params){ + char *p =params; + p +=3; + char *end = strchr(p, '&'); + int len = (int)(end-p); + substring(ServerNet.local_ip, p, 0,len); + p +=len; + p += 9; + end = strchr(p, '&'); + len = (int)(end-p); + substring(ServerNet.local_mask , p, 0, len); + p +=len; + p +=9; + end = strchr(p, '&'); + len = (int)(end-p); + substring(ServerNet.local_gw, p, 0, len); + p +=len; + p += 5; + strcpy(ServerNet.local_dns, p); +} + + +void HandleHttpRequest(char *params){ + SubstractServerNet(params); + AddrUpdate(); //修改本机参数信息; +} + +//设置socket +//循环监听socket并修改网络信息,单线程 +void tcpecho_thread(){ + int sock=-1, connected; + char *recv_data; + struct sockaddr_in server_addr, client_addr; + socklen_t sin_size; + int recv_data_len; + + recv_data = (char *) malloc(RECV_DATA); + + if(recv_data == NULL){ + printf("No memory"); + goto __exit; + } + + sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0){ + printf("Socket error\n"); + goto __exit; + } + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(PORT); + memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); + + if(bind(sock,(struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == 1){ + printf("Unable to bind\n"); + goto __exit; + } + if (listen(sock, 5) == -1) + { + printf("Listen error\n"); + goto __exit; + } + + while(1){ + sin_size = sizeof(struct sockaddr_in); + connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size); + + printf("new client connected from (%s, %d)\n", + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + + { + int flag = 1; + + setsockopt(connected, + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (void *) &flag, /* the cast is historical cruft */ + sizeof(int)); /* length of option value */ + } + + + recv_data_len = recv(connected, recv_data, RECV_DATA, 0); + + printf("recv %d len data\n",recv_data_len); + recv_data[recv_data_len] = '\0'; + printf("%s\n", recv_data); + + char * params = strstr(recv_data, "ip="); + HandleHttpRequest(params); + + char *response = "HTTP/1.1 200 OK\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n"; + write(connected,response,strlen(response)); + if (connected >= 0) + closesocket(connected); + + connected = -1; + } + __exit: + if (sock >= 0) closesocket(sock); + if (recv_data) free(recv_data); +} + +void TestWebserver(){ + tcpecho_thread(); +} + +PRIV_SHELL_CMD_FUNCTION(TestWebserver, Implement web_server, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_webserver/test_webserver.h b/APP_Framework/Applications/app_test/test_webserver/test_webserver.h new file mode 100644 index 000000000..105ff13c7 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_webserver/test_webserver.h @@ -0,0 +1,43 @@ +/** +* @file: test_webserver.h +* @brief: a application of test webserver function +* @version: 1.0 +* @author: Yao wenying +* @date: 2023/08/20 +*/ + + +#ifndef __WEBSERVER_H__ +#define __WEBSERVER_H__ + +#include "lwip/opt.h" +#include +#include "lwip/api.h" +#include "lwip/sys.h" +#include "netif/ethernet.h" +#include "lwip/tcpip.h" +#include "sys_arch.h" +#include +#include "dns.h" +#include "string.h" + + +#define PORT 80 +#define RECV_DATA 1024 +struct ServerNet +{ + char local_ip[20]; + char local_mask[20]; + char local_gw[20]; + char local_dns[20]; +}ServerNet; + +void LwipShowIP(); +void LwipSetIP(int argc, char *argv[]); +void ShowDns(); +void SetDns(); +void AddrUpdate(); //更新本机网络参数信息 +void HandleHttpRequest(); //解析报文,并返回响应 +void TcpThread();//建立socket监听,循环等待网络通信事件到来 + +#endif \ No newline at end of file