美文网首页物联网相关技术研究物联网loT从业者
ESP8266学习笔记(6)——简易HTTP客户端

ESP8266学习笔记(6)——简易HTTP客户端

作者: Leung_ManWah | 来源:发表于2018-11-27 18:12 被阅读3次

一、背景


已知智能网关固定IP地址192.168.100.1,智能插座连上智能网关AP热点后,向网关发起标定设备请求,因此需要ESP8266作为HTTP客户端角色。

Post请求和Get请求:


二、流程

2.1 定义相关结构体

struct espconn http_client_conn;            // 定义一个TCP连接结构体
LOCAL os_timer_t http_send_identify_timer;  // 定义一个定时器,因为连接上服务器瞬间发送消息会收不到

2.2 初始化HTTP客户端

/**
 @brief 初始化HTTP客户端
 @param remote_port 远程端口
 @return 无
*/
void ICACHE_FLASH_ATTR
user_httpclient_init(uint32 remote_port)
{
    struct ip_info info;
    struct ip_addr remote_ip;
    char buffer[68] = "192.168.100.1";
    remote_ip.addr = ipaddr_addr(buffer);                       // 点分十进制写入IP结构体
    // 配置
    http_client_conn.type = ESPCONN_TCP;
    http_client_conn.state = ESPCONN_NONE;
    http_client_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));
    wifi_get_ip_info(STATION_IF, &info);
    os_memcpy(http_client_conn.proto.tcp->local_ip, &info.ip, 4);
    os_memcpy(http_client_conn.proto.tcp->remote_ip, &remote_ip, 4);
    http_client_conn.proto.tcp->local_port = espconn_port();    // 获取可用端口作为本地端口
    http_client_conn.proto.tcp->remote_port = remote_port;
    // 注册连接成功和重连的回调函数
    espconn_regist_connectcb(&http_client_conn, http_client_connect_cb);
    espconn_regist_reconcb(&http_client_conn, http_client_recon_cb);
    // 连接服务器
    espconn_connect(&http_client_conn);
}

2.3 定义相关回调函数

/**
 @brief 成功接收到服务器返回数据函数
 @param arg 指向传入参数的指针
 @param pdata 字符串数组
 @param len 字符串数组长度
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_client_recv_cb(void *arg, char *pdata, unsigned short len)
{
    os_printf("httpclient_recvdata:\t%s\n", pdata);
}

/**
 @brief 发送数据到服务器成功的回调函数
 @param arg 指向传入参数的指针
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_client_send_cb(void *arg)
{
    os_printf("httpclient_send succeed!\n");
}

/**
 @brief 断开服务器成功的回调函数
 @param arg 指向传入参数的指针
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_client_discon_cb(void *arg)
{
    os_printf("httpclient_disconnect!\n");
}

/**
 @brief 连接失败的回调函数,err为错误代码
 @param arg 指向传入参数的指针
 @param err 为错误代码
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_client_recon_cb(void *arg, sint8 err)
{
    os_printf("httpclient connect error, error number:%d\r\n", err);
    espconn_disconnect((struct espconn *) arg);  // 连接失败后断开
}

/**
 @brief 成功连接到服务器的回调函数
 @param arg 指向传入参数的指针
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_client_connect_cb(void *arg)
{
    struct espconn *pespconn = arg;
    espconn_regist_recvcb(pespconn, http_client_recv_cb);
    espconn_regist_sentcb(pespconn, http_client_send_cb);
    espconn_regist_disconcb(pespconn, http_client_discon_cb);

    os_timer_disarm(&http_send_identify_timer);
    os_timer_setfn(&http_send_identify_timer, (os_timer_func_t *) http_send_identify_callback, NULL);
    os_timer_arm(&http_send_identify_timer, 2000, false);  // 开启发送设备认证请求的定时器
}

2.4 定时器到时后进入回调函数

/**
 @brief 发送设备认证定时器的回调函数
 @param 无
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_send_identify_callback(void)
{
    http_identify_device();   // 向核心路由器发送设备认证
}

/**
 @brief 发送设备认证
 @param 无
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_identify_device(void)
{
    char URL[32] = "192.168.100.1";
    unsigned short port = 8080;
    char postdata[128] = {0};
    char host[32] = {0};
    char filename[32] = {0};
    uint8 id_buf[20] = {0};
    unsigned int nId = 0;
        
    // 创建JSON数据包
    cJSON *Result = cJSON_CreateObject();
    cJSON * array = cJSON_CreateArray();
    cJSON_AddStringToObject(Result, "Module", "ServiceObject");
    cJSON_AddStringToObject(Result, "Func", "append");
    // 添加 Info 数组
    cJSON_AddItemToObject(Result,"Info",array);
    cJSON * array_item = cJSON_CreateObject();
    cJSON_AddItemToArray(array, array_item);
    os_sprintf(id_buf, "%x", system_get_chip_id());
    nId = HexStrToDec(id_buf);
    cJSON_AddNumberToObject(array_item, "id", nId);
    cJSON_AddNumberToObject(array_item, "type", 2);

    char *succeedData = cJSON_Print(Result);
    os_sprintf(postdata, "%s", succeedData);
    //os_printf("data:%s\n", postdata);

    http_post_request(URL, host, filename, &port, postdata);  // 发送POST请求
    cJSON_Delete(Result);
}

2.5 发送POST请求

#define GET "GET /%s HTTP/1.1\r\nContent-Type: text/html;charset=utf-8\r\nAccept: */*\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n"
#define POST "POST /%s HTTP/1.1\r\nAccept: */*\r\nContent-Length: %d\r\nContent-Type: application/json\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n%s"

/**
 @brief 解析URL
 @param tbd
 @return 无
*/
LOCAL void ICACHE_FLASH_ATTR
http_parse_request_url(char *URL, char *host, char *filename, unsigned short *port)
{
    char *PA;
    char *PB;

    memset(host, 0, sizeof(host));
    memset(filename, 0, sizeof(filename));

    *port = 0;

    if (!(*URL))
    {
        return;
    }

    PA = URL;

    if (!strncmp(PA, "http://", strlen("http://")))
    {
        PA = URL + strlen("http://");
    }
    else if (!strncmp(PA, "https://", strlen("https://")))
    {
        PA = URL + strlen("https://");
    }

    PB = strchr(PA, '/');

    if (PB)
    {
        memcpy(host, PA, strlen(PA) - strlen(PB));
        if (PB + 1)
        {
            memcpy(filename, PB + 1, strlen(PB - 1));
            filename[strlen(PB) - 1] = 0;
        }
        host[strlen(PA) - strlen(PB)] = 0;
    }
    else
    {
        memcpy(host, PA, strlen(PA));
        host[strlen(PA)] = 0;
    }

    PA = strchr(host, ':');

    if (PA)
    {
        *port = atoi(PA + 1);
    }
    else
    {
        *port = 80;
    }
}

/**
 @brief 发送POST请求
 @param tbd
 @return 无
*/
void ICACHE_FLASH_ATTR
http_post_request(char *URL, char *host, char *filename, unsigned short *port, char *postdata)
{
    char buffer[1024] = {0};
    http_parse_request_url(URL, host, filename, port);
    os_sprintf(buffer, POST, filename, strlen(postdata), host, postdata);
    os_printf("httpclient_data:\r\n%s\n", buffer);
    espconn_sent(&http_client_conn, buffer, strlen(buffer));
}

• 由 Leung 写于 2018 年 11 月 27 日

• 参考:[ESP8266 Non-OS SDK API参考]
    Esp8266学习之旅⑤ 8266原生乐鑫SDK高级使用之封装Post与Get请求云端,拿到“天气预报信息”

相关文章

网友评论

    本文标题:ESP8266学习笔记(6)——简易HTTP客户端

    本文链接:https://www.haomeiwen.com/subject/tzqnqqtx.html