Yeelink平台推送传感器结果——套接字编程 Windows平台

1.前言
    本文使用windows平台的socket套接字实现向yeelink平台推送传感器结果。
    【相关博文】
    【 MinGW安装和使用总结 】
    【Yeelink Http请求格式分析】
    【Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32 】
    【Yeelink平台查询开关量——套接字编程 Windows平台 】

2.运行
    【工作流程】    
    先看运行结果,大致的过程分为三块。第一部分,进行DNS地址解析;第二部分,发送HTTP请求;第三部分,接收HTTP响应
    【HTTP请求】
    POST /v1.0/device/1949/sensor/2510/datapoints HTTP/1.1
    Host: api.yeelink.net
    U-ApiKey: ffa3826972d6cc7ba5b17e104ec59fa3
    Content-Length:15

    {"value":20.30}
    【HTTP响应】省略其他部分
    HTTP/1.1 200 OK


图1 运行结果
    【运行设置】
    若使用minGW+eclipse开发方式,需要加入wsock32库,添加的方法如下:

图2 添加wsock32库
3.参考代码
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
// 请求缓冲区和响应缓冲区
char http_request[1024] = {0,};
char http_response[1024] = {0,};
// 主机IP地址,也可以是主机域名
char remote_server[] = "api.yeelink.net";
// 文件地址 RESTFUL形式
char remote_path[] = "/v1.0/device/1949/sensor/2510/datapoints";
// 用户密码 请修改
char apikey[] = "ffa3826972d6cc7ba5b17e104ec5XXXX";
int main(int argc, char **argv)
{
    WSADATA wsaData;
    int result;
    int socket_id;
    // 传感器检测结果
    double value = 20.3;
    // Http属性
    char http_attribute[64] = {0,};
    // Http内容,表单内容
    char http_content[64] = {0,};
    // 确定HTTP表单提交内容 {"value":20}
    sprintf( http_content , "{\"value\":%.2f}" , value);
    // 确定 HTTP请求首部
    // 例如POST /v1.0/device/1949/sensor/2510/datapoints HTTP/1.1\r\n
    char http_header[64] = {0,};
    sprintf( http_header , "POST %s HTTP/1.1\r\n",remote_path);
    strcpy( http_request , http_header ); // 复制到请求缓冲区中
    // 增加属性 例如 Host: api.yeelink.net\r\n
    sprintf( http_attribute , "Host:%s\r\n" , remote_server);
    strcat( http_request , http_attribute);
    memset( http_attribute , 0 , sizeof(http_attribute));
    // 增加密码 例如 U-ApiKey: ffa3826972d6cc7ba5b17e104ec59fa3
    sprintf( http_attribute , "U-ApiKey:%s\r\n" , apikey);
    strcat( http_request , http_attribute);
    memset( http_attribute , 0 , sizeof(http_attribute));
    // 增加提交表单内容的长度 例如 Content-Length:12\r\n
    sprintf( http_attribute , "Content-Length:%d\r\n" ,strlen(http_content) );
    strcat( http_request , http_attribute);
    memset( http_attribute , 0 , sizeof(http_attribute));
    // 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
    // 该步骤可省略
    strcat( http_request , "Content-Type:application/x-www-form-urlencoded\r\n");
    memset( http_attribute , 0 , sizeof(http_attribute));
    // HTTP首部和HTTP内容 分隔部分
    strcat( http_request , "\r\n");
    // HTTP负载内容
    strcat( http_request , http_content);
    // Winsows下启用socket
    result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        printf("WSAStartup failed: %d\n", result);
        return 1;
    }
    // DNS解析 获得远程IP地址
    struct hostent *remote_host;
    remote_host = gethostbyname(remote_server);
    if( remote_host == NULL )
    {
        printf("DNS failed\r\n");
        return 1;
    }
    // 创建套接字
    socket_id = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in remote_sockaddr;
    remote_sockaddr.sin_family = AF_INET;
    remote_sockaddr.sin_port = htons(80);
    remote_sockaddr.sin_addr.s_addr = *(u_long *) remote_host->h_addr_list[0];
    memset(&(remote_sockaddr.sin_zero), 0, sizeof(remote_sockaddr.sin_zero));
    // 连接远程主机
    result = connect( socket_id, (struct sockaddr *)&remote_sockaddr, sizeof(struct sockaddr));
    if( result == SOCKET_ERROR )
    {
        printf("connect ok\r\n");
    }
    // 发送请求
    printf("Http request:\r\n%s\r\n",http_request);
    printf("--------------------\r\n");
    send(socket_id , http_request, strlen(http_request), 0);
    // 获得响应
    int bytes_received = 0;
    bytes_received = recv( socket_id , http_response, 1024, 0);
    http_response[ bytes_received ] = '\0';
    printf("Receive Message:\r\n%s\r\n",http_response );
    printf("--------------------\r\n");
    // 判断是否收到HTTP OK
    char* presult = strstr( http_response , "200 OK\r\n");
    if( presult != NULL ) printf("Http response OK\r\n");
    // 关闭套接字
    closesocket(socket_id);
    WSACleanup();
   
    // 输入任何字符则关闭程序
    printf("Finish\r\n");getchar();
    return 0;
}

4.总结和展望
    socket是对TCP或者UDP通信的抽象,但是对于HTTP通信而言socket就显得比较麻烦了。以后的博文还会总结socket用法。

你可能感兴趣的:(socket,yeelink)