开发者中心

C使用TCP协议SDK接入实例

1. 下载C语言版本的SDK

从新大陆云平台下载C语言版本的SDK,目前提供Linux系统运行示例, 将代码放置Ubuntu中的/home目录下(或者其它),如下:

2. 建立TCP连接

在main.c中修改云服务器IP和端口,如下: #define SERVER_IP "121.37.241.174"
#define SERVER_PORT 8600
注意 : 请确保你的Ubuntu可以正常上公网

3. 设备与平台进行握手连接

使用记录好的“设备标识”“传输密钥”做为参数, 在main.c的post_process函数中,修改设备标识和传输密钥,组织TCP握手连接报文,发送到平台与之建立握手连接.

    
        /* 根据协议定义连接请求的结构体 */
        con_req.msg_type = PACKET_TYPE_CONN_REQ; 
        con_req.device_id = "qiuzhb";
        con_req.key= "677abb3a5ff3456fb831c96482f11536";
        con_req.ver = "V1.0";

        /* 利用SDK 中cloud.h 中 packet_msg 方法封包连接协议 */
        packet = packet_msg(&con_req);

        /*发送连接协议包数据*/
        ret = send_packet(sock, packet, strlen(packet), 0);

                

若握手连接成功,云端会发送响应成功信息,在设备管理中会看到一个在线标记: 若握手连接失败,云端也会发送响应失败信息,告诉失败原因。

4.添加传感及数据上报

利用SDK中提供的接口函数,编写代码将数据上报到平台。 以C语言SDK为例,上传一组温度为30℃,湿度为80%RH的数据。

                    
        //数据类型为1(JSON格式1字符串)
        post_req.msg_type = PACKET_TYPE_POST_DATA;
        post_req.msg_id++;
        post_req.data_type = 1;
        post_req.data = "{\
        \"nl_temperature\": \"23\",\
        \"nl_light\": 2000\
        }";
        post_req.data_len = strlen(post_req.data);
        packet = packet_msg(&post_req);
        if(packet == NULL){
	        MAIN_ERR("packet_msg JSON 1 error\n");
        }else{
	        MAIN_DBG("POST JSON 1 \n");
	        send_flag = 1;
        }

        /*发送包数据,上报传感数据*/
        if(send_flag){
	        ret = send_packet(sock, packet, strlen(packet), 0);
	        if(ret < 0){
		        MAIN_ERR("PACKET_TYPE_POST_DATA error\n");
	    }
	    free_packet_msg(packet);
	    send_flag = 0;
    }

                

5.重新生成新的可执行文件

输入“make clean”清除旧的可执行文件 ,再输入“make”重新生成新的可执行文件如下: 输入“./main”,运行程序,可以看到程序会自动连接云平台,在线的图标点亮; 并向云平台上传了温度和光照传感器数据,如下: 点击风扇的开关按钮,进行下行控制,如下: 同时在Ubuntu中会终端上能看到如下输出,即成功收到的下行命令:

        
        {
            "t":        6,
            "cmdid":    24061,
            "apitag":   "nl_fan",
            "data":     1
        }
        

Json/二进制格式数据传输实例

1. 简要说明

JSON是轻量级的数据交换格式,二进制也是网络通信中广泛采用的一种数制,平台支持这两种格式的数据上报及命令下发,需要做下转换,基本原理是 在TCP协议或MQTT协议中,针对数据的上报或下发都是基于JSON格式的,想在JSON格式协议中再包含JSON对象或二进制数据,分别将他们转化为字符串来传输,大致如下:

2. 关键代码解析

以Ubuntu环境、C语言开发的网关做为设备接入端,C#开发的上位机应用为例,介绍JSON的传输。
1)、在云平台添加相应的项目、设备、传感器、执行器,传感器与执行器如下图所示:
2)、C语言上传JSON与二进制的关键代码

                     
    //////////////////////////////////////////////数据上报格式//////////////////////////////////////////////
    {
        "t": 3,
        "datatype": 1,
        "datas": 
        {
	        "jsonsensor": "{\"UserName\":\"李四\",\"Age\":23,\"Sex\":1,\"IsMarry\":false}",    //JSON序列化为字符串
	        "binarysensor": "AQIDBAU="                         //{ 0x01, 0x02, 0x03, 0x04, 0x05 }经过Base64编码的字符串
        },
        "msgid": 123
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    

    //发送数据到平台函数
    int send_data_to_cloud(void)
    {
	    char jsonData[] =  "{\"UserName\":\"李四\",\"Age\":23,\"Sex\":1,\"IsMarry\":false}";
	    char binaryData[] = {0x02,0x04,0x06,0x08};
	    int binlength = 4;

	    int send_sock = tcpSend_fd_read();
	    send_json_data(send_sock, 1, jsonData);
	    sleep(5);

	    send_binary_data(send_sock, 2, binaryData, binlength);
	    sleep(5);

	    return 0;
    }

    //发送JSON数据函数
    int send_json_data(int sock,int msgid,char *jsonData)
    {
	    int ret;	
	    char data[512] = {0};

	    sprintf(data, "{\"t\":3,\"datatype\":1,\"msgid\":%d,\"datas\":{\"jsonsensor\":%s}}", msgid, jsonData);

	    printf("/********************************** SEND JSON DATA **********************************/\r\n");
	    printf("%s\r\n",data);
	    printf("/********************************** ************** **********************************/\r\n\r\n");
	
	    ret = send_packet(sock, data, strlen(data), 0);
	    if(ret < 0){
		    CLIENT_SEND_ERR("send packet to cloud fail\r\n");
		    return -1;
	    }

	    return 0;
    }
    
    //发送二进制数据函数
    int send_binary_data(int sock,int msgid,char *binaryData, int binlength)
    {

	    int ret;	

	    char data[512] = {0};
	    char base64[256] = {0};

	    ret = base64_encode(binaryData, base64, binlength);
	    if(ret == BASE64FAIL)
	    {
		    printf("binary to base64 faill\r\n");
		    return -1;
	    }
	

	    sprintf(data, "{\"t\":3,\"datatype\":1,\"msgid\":%d,\"datas\":{\"binarysensor\":\"%s\"}}", msgid, base64);

	    printf("/********************************* SEND Binary DATA *********************************/\r\n");
	    printf("%s\r\n",data);
	    printf("/********************************** ************** **********************************/\r\n\r\n");
	
	    ret = send_packet(sock, data, strlen(data), 0);
	    if(ret < 0){
		    CLIENT_SEND_ERR("send packet to cloud fail\r\n");
		    return -1;
	    }
	
	    return 0;
    }
                    
                

3)、云平台查询上传的数据记录
进入项目-》设备管理-》历史传感数据
4)、上位机应用获取数据关键代码

                
    //调用批量查询设备最新数据
    ResultMsg<IEnumerable<DeviceSensorDataDTO>> qry = SDK.GetDevicesDatas(Cfg.deviceId.ToString(), Token);
    Console.WriteLine(lineNum + "、批量查询设备最新数据返回JSON:" + Environment.NewLine);
    Console.WriteLine(SerializeToJson(qry) + Environment.NewLine);
    lineNum++;

    if (qry.IsSuccess())
    {
        var dev = qry.ResultObj.FirstOrDefault();
        try
        {
            SensorDataDTO jsonSensor = dev.Datas.FirstOrDefault(item => { return item.ApiTag == Cfg.jsonApiTag; });
            if (jsonSensor != null && jsonSensor.Value != null && jsonSensor.Value.ToString() != "")
            {
                //将设备传输的JSON字符串,使用JsonConvert转为对象
                Member user = new Member();
                user = JsonConvert.DeserializeObject<Member>(jsonSensor.Value.ToString());

                Console.WriteLine(lineNum + "、JSON传感器值:" + Environment.NewLine);
                Console.WriteLine(String.Format("{0}/{1}/{2}/{3}"
                    , user.UserName
                    , user.Age
                    , user.Sex
                    , user.IsMarry) + Environment.NewLine);
                lineNum++;
            }

            SensorDataDTO binarySensor = dev.Datas.FirstOrDefault(item => { return item.ApiTag == Cfg.binaryApiTag; });
            if (binarySensor != null && binarySensor.Value != null && binarySensor.Value.ToString() != "")
            {
                //将设备传输的Base64字符串,使用Base64解码为byte[]
                Byte[] ary = Convert.FromBase64String(binarySensor.Value.ToString());
                Console.WriteLine(lineNum + "、二进制传感器值:" + Environment.NewLine);
                Console.WriteLine(String.Format("{0}/{1}/{2}/{3}"
                    , ary[0]
                    , ary[1]
                    , ary[2]
                    , ary[3]) + Environment.NewLine);
                lineNum++;                                                                                  
            }
        }
        catch { }
    }
                
                

5)、上位机应用下发JSON与二进制关键代码

                
    //发送“JSON格式”的命令
    Member user = new Member() { UserName = "张三", Sex = 1, Age = Int32.Parse(CreateRandomNum(2)), IsMarry = false };
    String json = JsonConvert.SerializeObject(user);
    var qry = SDK.Cmds(Cfg.deviceId, Cfg.jsonActuator, json, Token);
    Console.WriteLine(lineNum + "、发送JSON格式命令返回JSON:" + Environment.NewLine);
    Console.WriteLine(SerializeToJson(qry) + Environment.NewLine);
    lineNum++;

    //发送“二进制格式”的命令
    byte[] ary = new Byte[] { 0x10, 0x09, 0x08, 0x07, 0x06 };
    String binary = Convert.ToBase64String(ary);
    qry = SDK.Cmds(Cfg.deviceId, Cfg.binaryActuator, binary, Token);
    Console.WriteLine(lineNum + "、发送二进制格式命令返回JSON:" + Environment.NewLine);
    Console.WriteLine(SerializeToJson(qry) + Environment.NewLine);
    lineNum++;
                
                

6)、设备端解析JSON与二进制命令关键代码

                
    static void control_command_deal(void* msg_unpacket)
    {
	    CMD_REQ* cmd_rcv = (CMD_REQ*)msg_unpacket;
	    int is_cmd_need_rsp = 0;
	    CMD_REQ_RSP* cmd_rsp = (CMD_REQ_RSP*)cmd_rcv;	//CMD_REQ struct is same with CMD_REQ_RSP struct

	    CLIENT_RCV_DBG("recv CMD, data type:%d\n", cmd_rcv->data_type);
	    switch(cmd_rcv->data_type){
		    case CMD_DATA_TYPE_NUM:
			    is_cmd_need_rsp = 1;
		
			    CLIENT_RCV_DBG("1.unpacket, msg_type:%d, msg_id:%d apitag:%s, data:%d\n", 
					    cmd_rcv->msg_type, cmd_rcv->cmd_id, cmd_rcv->api_tag, *((int*)cmd_rcv->data));
			    break;
		    case CMD_DATA_TYPE_DOUBLE:
			    is_cmd_need_rsp = 1;
			    CLIENT_RCV_DBG("2.unpacket, msg_type:%d, msg_id:%d apitag:%s, data:%f\n", 
					    cmd_rcv->msg_type, cmd_rcv->cmd_id, cmd_rcv->api_tag, *((double*)cmd_rcv->data));
			    break;
		    case CMD_DATA_TYPE_STRING:
			    is_cmd_need_rsp = 1;

			    CLIENT_RCV_DBG("3.unpacket, msg_type:%d, msg_id:%d apitag:%s, data:%s\n", 
					    cmd_rcv->msg_type, cmd_rcv->cmd_id, cmd_rcv->api_tag, (char*)cmd_rcv->data);

			    cJSON *msg_json = NULL;
			    msg_json = cJSON_Parse((char*)cmd_rcv->data);
			    if(msg_json != NULL)
			    {
					    if(msg_json->type == cJSON_Object){
					    cJSON *name_json = NULL;
					    cJSON *age_json = NULL;
					    name_json = cJSON_GetObjectItem(msg_json, "UserName");
					    if(name_json && name_json->type != cJSON_String){
						    CLIENT_RCV_ERR("name_json ->type(%d) error\n", name_json ->type);
						    return NULL;
					    }

					    age_json = cJSON_GetObjectItem(msg_json, "Age");
					    if(age_json && age_json->type != cJSON_Number){
						    CLIENT_RCV_ERR("age_json ->type(%d) error\n", age_json ->type);
						    return NULL;
					    }
					    printf("/================ RCV Str DATA ================/\r\n");
					    printf("msg_type:%d\r\n",cmd_rcv->msg_type);
					    printf("msg_id  :%d\r\n",cmd_rcv->cmd_id);
					    printf("apitag  :%s\r\n",cmd_rcv->api_tag);
					    printf("UserName:%s\r\n",name_json->valuestring);
					    printf("Age     :%d\r\n",age_json->valueint);
					    printf("/================ ======== ================/\r\n\r\n");

				    }
			    }
			    else
			    {
				    printf("/================ RCV Bin DATA ================/\r\n");
				    uint8_t bindata[256] = {0};
				    int len = base64_decode((char*)cmd_rcv->data, bindata);
				    printf("msg_type:%d\r\n",cmd_rcv->msg_type);
				    printf("msg_id  :%d\r\n",cmd_rcv->cmd_id);
				    printf("apitag  :%s\r\n",cmd_rcv->api_tag);
				    printf("apitag  :%s\r\n",cmd_rcv->data);
				    printf("changhex:");
				    print_hex(bindata,len);
				    printf("/================ ======== ================/\r\n\r\n");
			    }
				
			
			
			    CLIENT_RCV_DBG("3.unpacket, msg_type:%d, msg_id:%d apitag:%s, data:%s\n", 
					    cmd_rcv->msg_type, cmd_rcv->cmd_id, cmd_rcv->api_tag, (char*)cmd_rcv->data);
			    break;
		    case CMD_DATA_TYPE_JSON:
			    is_cmd_need_rsp = 1;
			    CLIENT_RCV_DBG("4.unpacket, msg_type:%d, msg_id:%d apitag:%s, data:%s\n", 
					    cmd_rcv->msg_type, cmd_rcv->cmd_id, cmd_rcv->api_tag, (char*)cmd_rcv->data);
			    break;
		    default:
			    CLIENT_RCV_ERR("data_type(%d) error\n", cmd_rcv->data_type);
	    }
	    if(is_cmd_need_rsp){
		    if(gataways_send_answer_to_cloud(cmd_rsp) == -1){
			    CLIENT_RCV_ERR("gataways_send_answer_to_cloud fail");
		    }
	    }
	
    }
                
                

7)、案例源代码下载
点击下载