如何上传数据到onenet云端设备上

onenet快速入门(本人资源中YunTD资源包提供一整套开发程序,可以使用linux+qt直接打开使用,需要的自行下载)
初次使用onenet云端设备的同志肯定会觉得有些陌生,虽然作为“物联网”的弄潮儿,网络让我们拉近彼此,有时候却会让人感觉咫尺天涯。接下来我就将自己的学习过程与大家分享分享。
## 学习思维分析 ##
1)首先你的明确onnet云端在网络中定位,onenet是一个开放性的云端服务器,初学者可以利用其开放特性,自己注册一个账户,这样你就拥有了属于自己的开发者中心,在中心按照引导进行虚拟设备创建,数据流创建,触发器创建等基本创建。你可能会问,创建这些有什么作用呢?
1.1虚拟设备创建:
顾名思义,你可以创建一个自己需要的虚拟设备,系统会自动的为你的设备分配对应的设备id,连接设备的APIKey,这相当于客户端上传数据的钥匙。而ip地址就相当于大门。
1.2数据流模板创建:
数据流模板的创建是为你客户端上传数据点或者数据流准备的,这样就相当于有一个指定的数据名字,如温度,湿度,一般是是英文的,这样你在客户端就可以向指定的数据流模板进行数据上传。
1.3触发器创建:
触发器创建可以实现对上传数据的实时监控,开发者可以自己定义在触发器中的触发条件,我就是使用邮箱进行触发事件的接收的。
2)接下来就是客户端,也是开发者耗时最长的。因为onene支持多种的通信协议,我使用的是最常见的TCP通信协议,这就需要开发者自行编辑基于TCP 通信协议的客户端编程,也称socket编程,完成有效的客户端编程是连接云端服务器的第一步,这儿思路如下
2.1 首先进行socket部分程序的编写,实现与云端IP端口的连接,这儿牵扯到云端数据上传与下载的报文格式,也就是说开发者需要按照指定格式向云端传输报文,云端会自动的解析开发者上传的数据,格式正确就会可以顺利的完成数据的上传和下载。
上传报文格式:

POST /devices/12xxx047/datapoints? HTTP/1.1
api-key: LAMC73uDUm=bK4Wrcrkpyxxxxxa4=
Host:api.heclouds.com
connection: close
Content-Length:66

{"datastreams":[{"id":"temperature","datapoints":[{"value":0}]}]} 

下载报文格式:

HTTP/1.1 200 OK"
Date: Mon, 02 Oct 2017 08:37:47 GMT"
Content-Type: application/json"
Content-Length: 603"
Connection: close"
Server: Apache-Coyote/1.1"
Pragma: no-cache"

注意:onenet支持数据上传格式为JSON数据格式 ,下载到的也是JSON格式的数据。这儿牵扯到JSON基本格式的学习,初学者不必纠结于原理,可以先运用最简单的单数据点上传,熟悉了之后可以学习JSON数据库进行多数据上传。
2.2编写socket应注意阅读服务器端的返回消息,返回消息可以直观的反应数据上传的失败与成功。程序需包含必要的容错处理,打印连接信息等,这样有利于快速发现错误,及时修正。初次连接的开发者大多数出出现的错误有
这是我 数据获取成功服务器返回的数据:

HTTP/1.1 200 OK
Date: Sun, 01 Oct 2017 14:07:12 GMT
Content-Type: application/json
Content-Length: 267
Connection: close
Server: Apache-Coyote/1.1
Pragma: no-cache
{"errno":0,"data":{"count":2,"datastreams":[{"datapoints":[{"at":"2017-10-01 21:33:56.682","value":0}],"id":"temperature"},{"datapoints":[{"at":"2017-09-14 20:20:31.099","value":[{"datapoints":[{"value":0}],"id":"temperature"}]}],"id":"datastreams"}]},"error":"succ"}

数据上传成功服务器返回的数据:

HTTP/1.1 200 OK
Date: Sun, 01 Oct 2017 13:33:55 GMT
Content-Type: application/json
Content-Length: 26
Connection: close
Server: Apache-Coyote/1.1
Pragma: no-cache

{"errno":0,"error":"succ"}

(1)上传数据的报文报头格式错误,服务器无法准确的解析
解决办法:开发者可以对比onenet官方的指定文档报文格式,注意自己设备ARKey和设备ID的不同
(2)上传数据点的格式错误,或者content-length(json数据串的字符个数)的数据不对
解决办法:初学者可以使用开发文档给定的进行测试,长度就不会存在问题,在熟悉之后可以使用strlen函数进行准确的字符串长度设定。这牵扯到多数据点上传,这儿不在赘述。

(4)初学者首次进行JSON数据串的编写会发现按照常规的字符串编写格式系统会报错,JSON数据中会使用大量的双引号,如果编写过程不处理,系统就会自行优化,选择最前面的,从而后面的就会报错。
解决方法:如下代码编写加上反斜杠进行双引号的区分

  char *Strcat(char *json,char *stream_id,float value){

    char json1[25]={0};
    strcat(json,"{\"datastreams\":[{");
    sprintf(json1,"\"id\":\"%s\",",stream_id);
    strcat(json,json1);
    strcat(json,"\"datapoints\":[");
    strcat(json,"{");
    sprintf(json1,"\"value\":%g",value);
    strcat(json,json1);
    strcat(json, "}]}]}");
    strcat(json, "\r\n");
    return json;
}  

下面是上传数据和下载数据的基本程序

#include"www.h"
http_post(向云端上传数据)
#include"www.h"
void geturl(char *url) {
    struct hostent  *purl=NULL;
    char myurl[BUFFSIZE], host[BUFFSIZE], 
         POST[BUFFSIZE],   request[BUFFSIZE],
         text[BUFFSIZE],  *phost = 0;
    int socketid, connectid, res, recvid, flag = 1;

    memset(myurl, 0, BUFFSIZE);
    memset(host, 0, BUFFSIZE);
    memset(POST, 0, BUFFSIZE);
    strcpy(myurl, url);

    // 得到path的位置
    for (phost = myurl; *phost != '/' && *phost != '\0'; ++phost);
    if ((int) (phost - myurl) == strlen(myurl)) {
        strcpy(POST, "/");
    } else {
        // 将访问路径保存到GET数组
        strcpy(POST, phost);
    }

   // 将path开始的位置设置为字符串结束标识,myurl到phost即为hos
    *phost = '\0';
    strcpy(host, myurl);

    socketid = socket(AF_INET, SOCK_STREAM, 0);
    if (socketid == -1) {
        printf("创建socket连接失败\n");
        exit(1);
    }
    printf("-> 创建socket连接成功\n");
    purl = gethostbyname(host);

    // 设置连接信息结构
    memset(&sockinfo, 0, sizeof(struct sockaddr_in));
    sockinfo.sin_family = AF_INET;
   // sockinfo.sin_addr.s_addr = *((unsigned long *)purl->h_addr_list[0]);
    sockinfo.sin_port = htons(PORT);
    inet_pton(AF_INET,"183.230.40.33",&sockinfo.sin_addr);
    // 构造http请求
    memset(request, 0, BUFFSIZE);
    Request(request,"POST ",POST);
    Strcat(request,"temperature",22.5);

    // 连接到远端服务器
    connectid = connect(socketid, (struct sockaddr*)&sockinfo, sizeof(sockinfo));
    if (connectid == -1) {
        printf("连接远端服务器失败\n");
        exit(1);
    }
    printf("-> 连接到远端服务器成功\n");
    // 向服务器发送GET请求
    res = send(socketid, request, strlen(request), 0);
    if (res == -1) {
        printf("向服务器发送POST请求失败\n");
        exit(1);
    }
    printf("-> 发送POST请求成功,共发送了%d bytes\n", res);
    printf("-> HTTP请求报文如下\n--------HTTP Request--------\n%s\n", request);
    printf("-> HTTP响应内容正在重定向至text\n");
    // 接受服务器的响应
    if (freopen("text", "w", stdout) == NULL) {
        printf("输出重定向错误\n");
        exit(1);
    } else {
        while (flag) {
            memset(text, 0, TEXT_BUFFSIZE);
            int bufflen = recv(socketid, text, TEXT_BUFFSIZE, 0);

            if (bufflen < 0) {
                printf("接收数据流出错\n");
                fclose(stdout);
                close(socketid);
                exit(1);
            }
            if (bufflen > 0) {
                printf("%s\n", text);
            } else {
               ag = 0;
            }
        }
    }
    fclose(stdout);
    close(socketid);
}

``
http_get(从云端获取数据)
include"www.h"
void geturl(char *url) {
struct hostent *purl=NULL;
char myurl[BUFFSIZE], host[BUFFSIZE],
POST[BUFFSIZE], request[BUFFSIZE],
text[BUFFSIZE], *phost = 0;
int socketid, connectid, res, recvid, flag = 1;

memset(myurl, 0, BUFFSIZE);
memset(host, 0, BUFFSIZE);
memset(POST, 0, BUFFSIZE);
strcpy(myurl, url);

// 得到path的位置
for (phost = myurl; *phost != '/' && *phost != '\0'; ++phost);
if ((int) (phost - myurl) == strlen(myurl)) {
    strcpy(POST, "/");
} else {
    // 将访问路径保存到GET数组
    strcpy(POST, phost);
}

// 将path开始的位置设置为字符串结束标识,myurl到phost即为hos
*phost = ‘\0’;
strcpy(host, myurl);

socketid = socket(AF_INET, SOCK_STREAM, 0);
if (socketid == -1) {
    printf("创建socket连接失败\n");
    exit(1);
}
printf("-> 创建socket连接成功\n");
purl = gethostbyname(host);

// 设置连接信息结构
memset(&sockinfo, 0, sizeof(struct sockaddr_in));
sockinfo.sin_family = AF_INET;

// sockinfo.sin_addr.s_addr = *((unsigned long *)purl->h_addr_list[0]);
sockinfo.sin_port = htons(PORT);
inet_pton(AF_INET,“183.230.40.33”,&sockinfo.sin_addr);
// 构造http请求
memset(request, 0, BUFFSIZE);
Request(request,"GET ",POST);

// 连接到远端服务器
connectid = connect(socketid, (struct sockaddr*)&sockinfo, sizeof(sockinfo));
if (connectid == -1) {
    printf("连接远端服务器失败\n");
    exit(1);
}
printf("-> 连接到远端服务器成功\n");
// 向服务器发送GET请求
res = send(socketid, request, strlen(request), 0);
if (res == -1) {
    printf("向服务器发送POST请求失败\n");
    exit(1);
}
printf("-> 发送GET请求成功,共发送了%d bytes\n", res);
printf("-> HTTP请求报文如下\n--------HTTP Request--------\n%s\n", request);
printf("-> HTTP响应内容正在重定向到text\n");
// 接受服务器的响应
if (freopen("text", "w", stdout) == NULL) {
    printf("输出重定向错误\n");
    exit(1);
} else {
    while (flag) {
        memset(text, 0, TEXT_BUFFSIZE);
        int bufflen = recv(socketid, text, TEXT_BUFFSIZE, 0);

        if (bufflen < 0) {
            printf("接收数据流出错\n");
            fclose(stdout);
            close(socketid);
            exit(1);
        }
        if (bufflen > 0) {
            printf("%s\n", text);
        } else {
            flag = 0;
        }
    }
}
fclose(stdout);
close(socketid);

}

仔细观察上述的上传和下载的代码,实际上二者区别并不是很大,代码基本的框架一样,这儿决定上传还是下载数据主要是取决上传报文的内容:

main函数


#include"www.h"
char *Request(char *request,char *command,char *post){
    
    strcat(request,command);
    strcat(request,post);
    strcat(request, " HTTP/1.1\r\n");
    // 以上为http请求行信息
    strcat(request, "api-key:");
    strcat(request," ***********");
    strcat(request, "\r\n");
    strcat(request, "Host:");
    strcat(request, "api.heclouds.com");
    strcat(request, "\r\n");
    strcat(request,"connection: close\r\n");
    strcat(request,"\r\n");
    return request;
}
char *add(char *buf1,char *device,char *id,char *datapoint)
{
    //char  buf1[10]={0};
    strcat(buf1,"/");
    strcat(buf1,device);
    strcat(buf1,"/");
    strcat(buf1,id);
    strcat(buf1,"/");
    strcat(buf1,datapoint);
    strcat(buf1,"?");
    return  buf1;
}
int main(int argc, char *argv[])
{  
    char get_buf[1024]={0};
    if (argc < 2) 
    { printf("请输入正确的URL参数\n");
         exit(1);
    }
   argv[1]=add(get_buf,argv[1],argv[2],argv[3]);
         geturl(argv[1]); 
         return 0;
}

www.h

#ifndef  __HTTP_H_
#define  __HTTP_H_
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUFFSIZE 4096
#define TEXT_BUFFSIZE 1024
#define PORT 80
    struct sockaddr_in sockinfo;
#endif

详细的可以进一步参考onnnet连接详细介绍

你可能感兴趣的:(物联网)