ESP8266模组SDK开发之HTTP编程
超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器;HTTP是一个属于应用层的面向对象的协议,由于其简捷、决速的方式,适用于分布式超媒体信息系统
超文本(Hyper Text)包含有超链接(Link)和各种多媒体元素标记(Markup)的文本。这些超文本文件彼此链接,形成网状(Web),因此又被称为网页(Web Page)。这些链接使用URL表示。最常见的超文本格式是超文本标记语言HTML
URL 即统一资源定位符(Uniform Resource Locator),用来唯一地标识万维网中的某一个文档。URL由协议、主机和端口(默认为80)以及文件名三部分构成。如:
HTTP工作原理如下图示
HTTP报文结构
- 请求报文:即从客户端(浏览器)向Web服务器发送的请求报文。报文的所有字段都是ASCII码
- 响应报文:即从Web服务器到客户端(浏览器)的应答。报文的所有字段都是ASCII码
- 请求方法:请求报文中的方法,是对所请求对象所进行的操作,也就是一些命令。
1. HTTP Client编程
HTTP Client功能开发:模拟http协议,访问百度首页www.baidu.com/index.html;串口打印出百度返回的数据
HTTP Client任务流程如下示:
实验步骤如下:
–> 在ESP8266_RTOS_SDK目录下新建httpclient文件夹,把station实验中的station目录下所有文件拷贝到该文件夹中
–> 在user目录下新建httpclient.c文件,并添加如下代码
/*******************httpclient.c***********************************************/
const char GetStr[] = "GET /index.html HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"\r\n";
#define HTTP_RCV_LEN 50000
void ATaskHttpClient( void *pvParameters ){
int iVariableExample = 0;
int fd = -1;
int NetTimeOnt = 20000;
int ret;
int i;
struct hostent *phostent;
struct sockaddr_in ServerAddr;
char *Httpmsg;
char *ipaddr = NULL;
STATION_STATUS StaStatus;
do{
StaStatus = wifi_station_get_connect_status();
vTaskDelay(100);
}while(StaStatus != STATION_GOT_IP);
fd = socket(PF_INET,SOCK_STREAM,0);
if(fd == -1){
printf("get socket fail!\n");
vTaskDelete(NULL);
return;
}
setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));
phostent = gethostbyname("www.baidu.com");
if(phostent == NULL){
printf("get host ip fail!\n");
vTaskDelete(NULL);
return;
}
else{
for(i = 0;phostent->h_addr_list[i];i++){
ipaddr = inet_ntoa(*(struct in_addr*)(phostent->h_addr_list[i]));
if(ipaddr != NULL){
printf("host addr is:%s\n", ipaddr );
break;
}
}
if(ipaddr == NULL){
printf("error:get ip fail!\r\n");
vTaskDelete(NULL);
return;
}
}
memset(&ServerAddr,0,sizeof(ServerAddr));
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(ipaddr);
ServerAddr.sin_port = htons(80);
ServerAddr.sin_len = sizeof(ServerAddr);
do{
ret = connect(fd,(struct sockaddr*)&ServerAddr,ServerAddr.sin_len);
if(ret != 0){
printf("connect is fail!\n");
vTaskDelay(100);
}
}while (ret != 0);
Httpmsg = zalloc(HTTP_RCV_LEN);
send(fd,GetStr,strlen(GetStr),0);
for(;;){
do{
ret = recv(fd,Httpmsg,50000,0);
if(ret > 0){
printf("%s",Httpmsg);
}
else{
printf("HttpServer data is no!\n");
}
}while(ret == -1);
}
free(Httpmsg);
vTaskDelete( NULL );
}
//HttpClient_init 初始化
void HttpClient_init(void){
xTaskCreate(ATaskHttpClient, "HttpClient", 256, NULL, 4, NULL);
}
–> 在include目录下新建httpclient.h文件,并添加声明
void ATaskHttpClient(void *pvParameters);
void HttpClient_init(void);
–> 在user_main.c文件中的user_init()函数下添加如下代码
#define SSID "Hotspot" //ESP8266要加入的无线网
#define PASSWORD "88888888"
void ICACHE_FLASH_ATTR
user_init(void){
printf("SDK version:%s\n", system_get_sdk_version());
Led_init();
wifi_set_opmode(STATION_MODE);
struct station_config *config = (struct station_config *)\
zalloc(sizeof(struct station_config));
sprintf(config->ssid,SSID);
sprintf(config->password,PASSWORD);
wifi_station_set_config(config);
free(config);
wifi_station_set_auto_connect(TRUE);
HttpClient_init();
xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}
–> 在ESP8266编译器中编译完成,烧写bin文件到ESP8266,打开串口助手,即可接收到百度服务器返回的数据
2. HTTP Server编程
HTTP Server功能开发:模拟httpserver等待网页访问;PC访问网页,查看网页信息
HTTP Server任务流程如下示:
实验步骤如下:
–> 在ESP8266_RTOS_SDK目录下新建httpserver文件夹,把station实验中的station目录下所有文件拷贝到该文件夹中
–> 在user目录下新建httpserver.c文件,并添加如下代码
/*******************httpserver.c***********************************************/
#define SERVERADDR "192.168.191.29" //esp8266连上WiFi后的IP地址
#define SERVERPORT 8000
//ATaskHttpServer任务
const char *DefaultPage=
"<html>"
"<head>"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
"<title>欢迎进入html世界</title>"
"</head>"
"<body>"
"<P>欢迎关注微信公众号:andyxi_linux</P>"
"</body>"
"</html>";
// 发送200 ok报头
int file_ok(int cfd, long flen){
char *send_buf = zalloc(sizeof(char)*100);
sprintf(send_buf, "HTTP/1.1 200 OK\r\n");
send(cfd, send_buf, strlen(send_buf), 0);
sprintf(send_buf, "Connection: keep-alive\r\n");
send(cfd, send_buf, strlen(send_buf), 0);
sprintf(send_buf, "Content-Length: %ld\r\n", flen);
send(cfd, send_buf, strlen(send_buf), 0);
sprintf(send_buf, "Content-Type: text/html\r\n");
send(cfd, send_buf, strlen(send_buf), 0);
sprintf(send_buf, "\r\n");
send(cfd, send_buf, strlen(send_buf), 0);
free(send_buf);
return 0;
}
//ATaskHttpServer 任务
void ATaskHttpServer( void *pvParameters ){
int iVariableExample = 0;
int fd = -1;
int cfd = -1;
int NetTimeOnt = 2000;
int ret;
struct sockaddr_in ServerAddr;
struct sockaddr ClientAddr;
socklen_t ClientAddrlen = sizeof(struct sockaddr);
char *Httpmsg;
char *Sendmsg;
STATION_STATUS StaStatus;
do{
StaStatus = wifi_station_get_connect_status();
vTaskDelay(100);
}while(StaStatus != STATION_GOT_IP);
fd = socket(PF_INET,SOCK_STREAM,0);
if(fd == -1){
printf("get socket fail!\n");
vTaskDelete(NULL);
return;
}
setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));
memset(&ServerAddr,0,sizeof(ServerAddr));
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = INADDR_ANY;
ServerAddr.sin_port = htons(SERVERPORT);
ServerAddr.sin_len = sizeof(ServerAddr);
if(bind(fd,(struct sockaddr*)&ServerAddr,ServerAddr.sin_len) != 0){
printf("bind socket fail!\n");
vTaskDelete(NULL);
return;
}
if(listen(fd,5) != 0){
printf("listen socket fail!\n");
vTaskDelete(NULL);
return;
}
Httpmsg = (char*)zalloc(sizeof(char)*1000);
for(;;){
cfd = accept(fd,&ClientAddr,&ClientAddrlen);
if(cfd != -1){
printf("HttpClient accept\n");
ret = recv(cfd,Httpmsg,1000,0);
if(ret > 0){
printf("HttpClient recv\n");
printf("%s\n",Httpmsg);
file_ok(cfd,strlen(DefaultPage));
send(cfd,DefaultPage,strlen(DefaultPage),0);
}
else{
printf("HttpClient data is no!\n");
}
}
close(cfd);
}
free(Httpmsg);
vTaskDelete( NULL );
}
//HttpServer_init 初始化
void HttpServer_init(void){
xTaskCreate(ATaskHttpServer, "HttpServer", 256, NULL, 4, NULL);
}
–> 在include目录下新建httpserver.h文件,并添加声明
void ATaskHttcpserver( void *pvParameters );
void Httpserver_init(void);
–> 在user_main.c文件中的user_init()函数下添加如下代码
#define SSID "Hotspot" //PC端和ESP8266要加入的无线网
#define PASSWORD "88888888"
void ICACHE_FLASH_ATTR
user_init(void){
printf("SDK version:%s\n", system_get_sdk_version());
Led_init();
wifi_set_opmode(STATION_MODE);
struct station_config *config = (struct station_config *)\
zalloc(sizeof(struct station_config));
sprintf(config->ssid,SSID);
sprintf(config->password,PASSWORD);
wifi_station_set_config(config);
free(config);
wifi_station_set_auto_connect(TRUE);
HttpServer_init();
xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}
–> 在ESP8266编译器中编译完成,烧写bin文件到ESP8266,模组复位后,确保PC与ESP8266在同一个网络中,在浏览器中输入ESP8266的IP地址,即可访问到ESP8266返回的网页信息