ESP8266模组SDK开发之HTTP编程

超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器;HTTP是一个属于应用层的面向对象的协议,由于其简捷、决速的方式,适用于分布式超媒体信息系统

超文本(Hyper Text)包含有超链接(Link)和各种多媒体元素标记(Markup)的文本。这些超文本文件彼此链接,形成网状(Web),因此又被称为网页(Web Page)。这些链接使用URL表示。最常见的超文本格式是超文本标记语言HTML

WiFi开发|ESP8266模组SDK开发之HTTP编程_http

URL 即统一资源定位符(Uniform Resource Locator),用来唯一地标识万维网中的某一个文档。URL由协议、主机和端口(默认为80)以及文件名三部分构成。如:

WiFi开发|ESP8266模组SDK开发之HTTP编程_client_02

HTTP工作原理如下图示
WiFi开发|ESP8266模组SDK开发之HTTP编程_WiFi_03

HTTP报文结构

  • 请求报文:即从客户端(浏览器)向Web服务器发送的请求报文。报文的所有字段都是ASCII码

WiFi开发|ESP8266模组SDK开发之HTTP编程_http_04

  • 响应报文:即从Web服务器到客户端(浏览器)的应答。报文的所有字段都是ASCII码

WiFi开发|ESP8266模组SDK开发之HTTP编程_server_05

  • 请求方法:请求报文中的方法,是对所请求对象所进行的操作,也就是一些命令。

WiFi开发|ESP8266模组SDK开发之HTTP编程_client_06

1. HTTP Client编程

HTTP Client功能开发:模拟http协议,访问百度首页www.baidu.com/index.html;串口打印出百度返回的数据

HTTP Client任务流程如下示:

判断是否获取到IP
创建socket
设置接收超时时间
获取域名IP
赋值server信息
连接到server
发送数据到server
从server接收数据

实验步骤如下:

–> 在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任务流程如下示:

判断是否获取到IP
创建socket
设置接收超时时间
赋值server信息
绑定socket
监听socket
处理Client连接
接收client数据
发送数据到client
关闭socket

实验步骤如下:

–> 在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返回的网页信息

WiFi开发|ESP8266模组SDK开发之HTTP编程_WiFi_07