请选择 进入手机版 | 继续访问电脑版
素材分类
hot西工大

2017年12月19日,西工大-云创大数据联合实验室签约仪式暨揭牌仪式在西北工业大学长安校区计算机学院隆重举 详细

QQ物联局域网通信SDK下载

[复制链接]
admin 发表于 2015-11-20 18:01:10 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
局域网通信SDK下载

QQ物联局域网通信SDK采用cgi/fast-cgi的形式,通过HTTP服务提供设备与客户端在局域网中通信的能力,实现对设备文件的管理


鉴于市场上现有的wifi+存储的设备中,大多数都提供HTTP服务,为了节省设备运算和存储空间,在原有WEB服务器上增加cgi扩展是不错的选择。
对于设备原系统不提供WEB服务器的情况,可以考虑uhttpd,具体见下文的 uhttpd web 服务器。
SDK以cgi或者fast-cgi的方式运行,只需更改编译选项即可。
经过一段时间的实测,我们觉得fast-cgi可以更高效地处理客户端请求,如果设备的WEB服务器允许,请使用fast-cgi选项编译SDK。


SDK以C语言代码提供。


建议使用Ubuntu14作为开发环境,安装CMake作为跨平台编译工具


SDK使用步骤

  • 修改配置 solution/qqiot_config.h
  • SDK初始化,完成后SDK能够运行起来,示例在 solution/device_init.c #int device_init()
  • 实现获取设备信息的函数,示例同样在 solution/device_init.c
SDK配置文件 qqiot_config.h
调试

  • 可以使用 IOT_Trace(...) 宏来输出调试信息
  • 在配置文件solution/qqiot_config.h 中定义#define _DEV_DEBUG_,可以开启调试模式,输出调试信息到文件
  • 定义 #define FTRACE_OUTPUT_FILE "/tmp/debug_out.cgi.log" ,可指定输出日志文件的路径
  • 打开调试会稍微增加程序文件的大小,稍微减慢执行速度。

写文件开关
如果允许客户端改写设备上的文件,比如上传文件,文件改名,删除文件

  • 在配置文件 solution/qqiot_config.h 中定义 #define QQIOT_DEVICE_WRITABLE

客户数据库开关
为客户端提供设备数据库,用于轻客户端记录一些数据,目前的用途有下载、上传历史任务记录

  • 在配置文件 solution/qqiot_config.h 中定义 #define QQIOT_DEVICE_DB

数据加密
QQ物联轻客户端使用HTML5界面,与设备直接通信时只能使用HTTP或者HTTPS,其中HTTPS对于移动设备并无太大意义,而HTTP通信又是明文。为尽量加强通信安全,SDK提供XTEA加密支持,用于加密设备返回的文件列表、文件信息,但是由于HTML5界面的限制,目前不能加密文件内容。

  • 在配置文件 solution/qqiot_config.h 中定义 #define USE_ENC_XTEA128 即可开启XTEA加密支持
  • 或者生成makefile时,加入选项: -DENC=xtea

跨域调用
默认情况下,浏览器会限制跨域AJAX调用,解决办法之一是HTTP返回中添加HTTP头:
Access-Control-Allow-Origin: *
注意同样的HTTP Header每次请求只能有一行,如果 HTTP SERVER 配置加了这么一行,程序里再加一行,会造成冲突

  • 在配置文件 solution/qqiot_config.h 中定义 #define ADD_ACCESS_CONTROL_ALLOW_ORIGIN 即可允许跨域调用
SDK初始化 device_init.c
初始化,示例文件solution/device_init.c
  1. int device_init()
  2. {
  3.     /* 设备配置信息 */
  4.     DeviceConfig    configInfo  = {0};
  5.     /* 设备标识信息 */
  6.     QQIOT_SIGN  signInfo    = {0};

  7.     /************************************************************************
  8.     *    start of configuration   *
  9.     /************************************************************************/

  10.     /* 1,指定一个路径,用于保存设备配置、来访用户信息,占用空间100K左右 */
  11. #ifdef __linux__
  12.     const char* conf_dir    = "/etc/qqiot/";
  13. #else
  14.     const char* conf_dir    = "d:\\qqiot\\";
  15. #endif

  16. #ifdef  READ_CONFIG_FILE
  17.     // 2, 读取设备信息,包括PID和Licence, 以及其它可以记录在文件的信息
  18.     // 2.1, 可以从文件读取 /
  19.     {
  20.         char    licence_file[1024]  = {0};
  21.         strcpy(licence_file, conf_dir);
  22.         strcat(licence_file, "qqiotws.conf");
  23.         IOT_Trace("READ LICENCE: %d, %s", strlen(licence_file), licence_file);

  24.         if (licence_file && licence_file[0])
  25.         {
  26.             QQIOT_FILE  *pfile  = NULL;

  27.             pfile   = fopen(licence_file, "r");

  28.             if (pfile)
  29.             {
  30.                 IOT_Trace("device_init() @02.06, %s", licence_file);
  31.                 qqiot_read_config(pfile, &signInfo, &configInfo);

  32.                 fclose(pfile);
  33.             }
  34.         }
  35.     }

  36. #else   // READ_CONFIG_FILE
  37.     // 2.2,也可以从管道通信读取 /
  38.     {
  39. #ifdef _DEV_DEBUG_
  40.         const char* licence_pipe    = "echo AdminId=ASDFGH\n"
  41.                                         "echo PID=1000000523\n"
  42.                                         "echo SN=4D278F302B2B4bbd\n"
  43.                                         "echo Licence=3045022025968274D841DC620E46F63206721D64D1873F07DB4EAD25729FF57AF53089B0022100D17D67C485F7B9E33A1B804C9DFE69548C39DB4A846128FF9E7F7E966D098A1B\n"
  44.                                         "echo MacAddress=11:22:33:44:55:66\n"
  45.                                         "echo DataDir=/tmp/mnt/USB-disk-b1/qqiot\n"
  46.                                         ;
  47. #else
  48.         const char* licence_pipe    = "cfg get pid\n"
  49.                                         "cfg get sn\n"
  50.                                         "cfg get licence\n"
  51.                                         "cfg get adminid\n"
  52.                                         "cfg get MacAddress\n"
  53.                                         "cfg get DataDir\n"
  54.                                         ;
  55. #endif

  56.         if (licence_pipe && licence_pipe[0])
  57.         {
  58.             QQIOT_FILE  *pfile  = NULL;

  59.             pfile   =   popen(licence_pipe, "r");
  60.             if (pfile)
  61.             {
  62.                 IOT_Trace("device_init() @02.07, %s", licence_pipe);
  63.                 qqiot_read_config(pfile, &signInfo, &configInfo);

  64.                 pclose(pfile);
  65.             }
  66.         }
  67.     }
  68. #endif  // READ_CONFIG_FILE

  69.     // 3, 填充 DEVICE_INFO 结构体,其中字段含义及取值见 qqiot_wifi_store_def.h /
  70.     DEVICE_INFO device_info = {0};
  71.     {
  72.         device_info.deviceName  = "QQ WIFI Disk";
  73.         device_info.displayName = "QQ 无线网盘";
  74.         device_info.deviceVersion   = "V1.0.0";

  75.         device_info.wifiMAC = configInfo.mac_address;   /* WIFI 的mac地址 */
  76.         device_info.fileType    = "1,2,3,4,5,10,11";    /* 支持文件分类 */

  77.         device_info.initAccess  = USER_Denied;  /* 默认用户权限 */

  78.         device_info.checkDownloadSession    = 1;    /* 下载文件是否验证登录信息 */
  79.     }

  80.     // 4, 填充 DEVICE_DIR 结构体,指定设备的一些工作目录 /
  81.     {
  82.         g_device_dir.defaultHome    = "/tmp/mnt";
  83.         g_device_dir.data   = configInfo.data_dir;

  84.         /* 图标URL, 注意fcgi初始化时,有可能获取不到host name,在此拼接URL很可能不对。写死URL也不一定正确:ip地址可能会变,即便设备提供DNS,手机也不一定会用设备的DNS服务,不推荐直接写URL。 */
  85.         g_device_dir.deviceIcon = "http://192.168.1.254/qqiot_ws_device_icon.png";      
  86.         /* 或者相对URL路径。此路径为相对于站点根目录的路径,输出时自动加上host name,比直接写URL靠谱,推荐用这种方式。*/
  87.         g_device_dir.deviceIcon = "/qqiot_ws_device_icon.png";

  88.         g_device_dir.photo  = "/tmp/mnt/USB-disk-b1/photo";     /* 照片文件夹 */
  89.         g_device_dir.video  = "/tmp/mnt/USB-disk-b1/test_misc";     /* 视频文件夹 */
  90.     }

  91.     // 5, 指定设备信息服务函数,这些函数需要实现 /
  92.     DeviceServiceFunc   device_func = {0};
  93.     {
  94.         device_func.get_download_url    = get_download_url_XSendfile;   /* 生成文件下载URL的函数 */
  95.         device_func.get_disk_info       = get_disk_info_df; /* 取存储空间的函数 */
  96.         device_func.excmd_proc          = excmd_proc;   /* 扩展命令处理函数 */
  97.     }

  98.     // 6, 指定媒体信息服务函数,这些函数需要实现 /
  99.     MediaInfoFunc   media_info_func = {0};
  100.     {
  101.         media_info_func.get_media_info  = fake_get_media_info;  /* 取媒体信息的函数 */
  102.         media_info_func.get_thumb_url   = fake_get_thumb_url;   /* 取缩略图URL的函数 */
  103.     }

  104.     /************************************************************************/
  105.     /*    end of configuration   */
  106.     /************************************************************************/


  107.     /* 7, 设备初始化 */
  108.     /************************************************************************/
  109.     /*    start of device init                                              */
  110.     /************************************************************************/
  111.     mkdir(conf_dir, "755");
  112.     qqiot_init(conf_dir, NULL);

  113.     qqiot_set_sign(&signInfo);
  114.     /*  设备信息变化、路径变化时,随时可调用 qqiot_set_device_service()和qqiot_set_device_info() 设置新的信息  */   
  115.     qqiot_set_device_service(&device_func);
  116.     qqiot_set_device_info(&device_info);
  117.     qqiot_set_device_dir(&g_device_dir);
  118.     IOT_Trace("device_init() @02.05");

  119.     init_media_service(&media_info_func);

  120.     /* 8, 所有事情做完之后,记得清理资源,以免内存泄漏。 */
  121.     /************************************************************************/
  122.     /*    start of clean up                                                 */
  123.     /************************************************************************/
  124.     /*  清理数据库多余内容,每次重启服务之后,旧的session理应清除。 */
  125.     qqiot_clear_session();

  126.     /*   清理临时内存 */
  127.     qqiot_free(signInfo.PID);
  128.     qqiot_free(signInfo.SN);
  129.     qqiot_free(signInfo.License);
  130.     qqiot_free(signInfo.AdminId);

  131.     qqiot_free(configInfo.data_dir);
  132.     qqiot_free(configInfo.mac_address);

  133.     return  0;
  134. }
复制代码




需要实现的函数

device_init.c 提供一种可行方案,请根据设备实际情况实现下面5个函数
  1. /* 获取客户可用磁盘信息 */
  2. int get_disk_info_df(_Out_ QQIOTDiskInfo* disk_info, _In_ int size, _Inout_ int *count, _In_ int offset);

  3. /* 获取指定文件下载URL */
  4. int get_download_url_XSendfile(_Out_ char *sz_url, int size, const char* path, const char *session_id);

  5. /* 执行扩展命令 */
  6. int excmd_proc(const char* content, int length, const USER_INFO *user_info, _Inout_ struct cJSON *response);

  7. /* 取指定文件媒体信息 */
  8. void get_media_info(const char* path, _Out_ VideoInfo *video_info, _Out_ AudioInfo *audio_info);

  9. /* 取指定文件缩略图 */
  10. int get_thumb_url(_Out_ char *sz_url, int size, const char* path, const char *session_id);
复制代码


扩展命令

除了提供文件管理功能以外,QQ物联局域网通信SDK提供扩展命令接口,可以利用这个接口实现不同设备的特定业务。
使用扩展命令实现的案例:
在手机端播放行车记录仪的历史视频时会占用设备的IO和CPU处理能力,导致设备端录像和播放视频功能同时使用时,录像丢帧,播放卡顿。
在不修改硬件的前提下,播放视频时给设备一个通知并停止录像,是一个可行的方案。
所以在手机端播放视频开始、暂停、停止时,可以通过扩展命令接口向设备发送自定义的视频播放事件,设备端接到事件之后做相应处理。
示例见 device_init.c 文件的函数
int excmd_proc(const char* content, int length, const USER_INFO *user_info, _Inout_ struct cJSON *response)

清理资源
在每个函数的实现中,不用的内存注意及时清理。
device_init.c 中还需实现一个函数 int device_uninit(),在FCGI结束运行时会调用这个函数,可以用来清理全局资源。

编译 CGI
建议使用 CMake 工具生成 makefile ,默认的CMakeList.txt 配置为将项目编译为CGI。
编译方法:
  1. cmake . -DENC=xtea
  2. make
复制代码


编译 FastCGI

建议使用 CMake 工具生成 makefile ,如果要将项目编译为FCGI,需要加一个开关。
编译方法:
  1. cmake . -DENC=xtea -DBUILD_PROJECT=fcgi
  2. make
复制代码


uhttpd web 服务器

以 Android 环境为例。
原则上只要是支持cgi或者fcgi的web服务器,都可以支持QQ物联局域网通信SDK,但是一般Android系统不提供Web Server。
我们在SDK中提供移植 uhttpd 的方法, uhttpd 是一个非常轻量的 Web Server,编译之后加上它的依赖库只占用130KB左右的空间。
可以使用NDK构建,以 Ubuntu14 作为开发环境。
1, 下载安装NDK。 http://developer.android.com/intl/zh-cn/ndk/downloads/index.html
2, 下载SDK包并解压。
3, 修改编译环境配置:编辑文件third/uhttpd/build/make_proj_android.sh,修改其中的变量:
  1. export HOST_SYS=linux-x86_64    #改成您的开发环境机器类型。
  2.     export NDK="/dir/to/Android/NDK/android-ndk-r10e.linux/"    #改成您的NDK所在目录
  3.     export ST_TOOLCHAIN="/tmp/arm_android.toolchain"    #生成独立工具链的目录。
  4.     export ANDROID_PLATFORM="android-9"     #您的目标 Android 平台版本,见 http://developer.android.com/intl/zh-cn/about/dashboards/index.html
复制代码


4, 编译:
  1. cd dir/to/sdk/third/uhttpd/
  2.     ./build/make_proj_android.sh
复制代码


5, 把cgi文件复制到cgi目录,启动服务程序
  1. export LD_LIBRARY_PATH=./usr/lib
  2.     mkdir /www
  3.     mkdir /www/cgi-bin
  4.     cp usr/bin/qqiot /www/cgi-bin/
  5.     ## 启动服务
  6.     ./usr/bin/uhttpd -f -h /www -r QQIOTWS -x /cgi-bin  -t 60 -T 30 -k 20 -A 1 -n 3 -N 100 -R -p 0.0.0.0:3280 -p [::]:3280 -p 0.0.0.0:80 -p [::]:80
  7.     ## 注意这里的cgi处理路径是 `/cgi-bin/qqiot` 在 `控制器入口配置` 时需要注意
复制代码


nginx WEB 服务器配置

修改WEB服务器,转发HTTP请求到qqiot_ws_fcgi处理。
以 nginx 为例:配置示例在 ./solution/nginx.conf。
  1. server {
  2.     ## 建议使用3280端口或者默认的80端口处理qqiot的请求。
  3.     listen       3280;

  4.     client_max_body_size 4096M;     ## 确保上传大文件不会出错
  5.     client_body_buffer_size 128k;
  6.     ...

  7.     ## qqiot路径的设置:
  8.     location = /qqiot {
  9.         fastcgi_pass 127.0.0.1:9000;    ## 转发到本机的9000端口监听的FCGI,注意ip地址和端口都要与FCGI监听地址一致
  10.         fastcgi_param QUERY_STRING $query_string;   ## FCGI所需参数
  11.         fastcgi_param REQUEST_METHOD $request_method;   ## FCGI所需参数
  12.         fastcgi_param CONTENT_TYPE $content_type;
  13.         fastcgi_param CONTENT_LENGTH $content_length;
  14.         fastcgi_param  REMOTE_ADDR        $remote_addr;
  15.         fastcgi_param  REMOTE_PORT        $remote_port;
  16.         fastcgi_param  SERVER_ADDR        $server_addr;
  17.         fastcgi_param  SERVER_PORT        $server_port;
  18.         fastcgi_param  SERVER_NAME        $server_name;
  19.         fastcgi_pass_header Cookie;         ## 转发cookie
  20.         fastcgi_intercept_errors        on;

  21.         ## add_header Access-Control-Allow-Origin *;       //允许跨域调用,方便H5页面调用,注意此行与 ADD_ACCESS_CONTROL_ALLOW_ORIGIN 有冲突
  22.     }
  23. }
复制代码


FastCGI 管理服务器

nginx并不能直接处理fast-cgi请求,而是需要fast-cgi管理服务器作为中转,推荐采用 spawn-fcgi。
参考 http://redmine.lighttpd.net/projects/spawn-fcgi
third/spawn-fcgi 目录下有其代码,编译:
  1. cd third/spawn-fcgi
  2. cmake .
  3. make
  4. make install
复制代码


运行 FastCGI

使用spawn-fcgi启动我们的FastCGI:
  1. sudo killall qqiot_ws_fcgi
  2. ## 在9000端口监听, -a 127.0.0.1 为限定只处理本机请求,注意WEB服务器的转发地址也应当是这个
  3. sudo /dir/to/spawn-fcgi -a 127.0.0.1 -p 9000 -f /dir/to/sdk/qqiot_ws_fcgi
复制代码


apache 服务器 cgi 配置

在apache的配置文件 httpd.conf 中添加以下行:
  1.     scriptalias /qqiot "/dir/to/qqiot_ws"
复制代码


OpenWRT

可以移植到 OpenWRT, 方法:
1, 把 solution/OpenWRT/package/qqiot_ws/ 文件夹移动到您的 OpenWRT 开发包的 package 目录
2, 把项目中所有文件复制到OpenWRT开发包下的 OpenWRT/package/qqiot_ws/src/ 目录
3, 在OpenWRT开发包目录下,运行 make menuconfig, 选择其中的 /Utilities/qqiot_ws 并保存退出
4, 运行 make 编译

交叉编译
利用 CMake 的 CMAKE_TOOLCHAIN_FILE 可以很方便地移植到目标平台,以海思为例:
1, 打开 HiSilicon.ToolChain.CMake.txt ,修改 TOOL_CHAIN_ROOT_DIR 为您的编译工具链目录。
2, 运行: cmake . -DENC=xtea -DCMAKE_TOOLCHAIN_FILE=./HiSilicon.ToolChain.CMake.txt
3, 运行 make 编译

测试
如果一切顺利,把以下地址换成设备真实地址,在浏览器中访问,可以取得设备信息:
http://address.to.device:port/qqiot?cmd=info&client=1
  1. {
  2.     "code": 0,
  3.     "response": {
  4.         "deviceName":   "QQ WIFI Disk",
  5.         "displayName":  "QQ 无线网盘",
  6.         "deviceVersion":    "V1.0.0",
  7.         "qqiotVersion": "1.0",
  8.         "deviceIcon":   "http://10.97.57.107:3280/qqiot_ws_device_icon.png",
  9.         "PID":  "1000000523",
  10.         "SN":   "4D278F302B2B4bbd",
  11.         "Licence":  "3045022025968274D841DC620E46F63206721D64D1873F07DB4EAD25729FF57AF53089B0022100D17D67C485F7B9E33A1B804C9DFE69548C39DB4A846128FF9E7F7E966D098A1B",
  12.         "DIN":  "",
  13.         "owner":    "",
  14.         "ownerName":    "",
  15.         "home": "/",
  16.         "fileType": "1,2,3,4,5,10,11",
  17.         "writable": true,
  18.         "defaultAccess":    -1,
  19.         "deviceDB": true,
  20.         "dirPhoto": "/photo",
  21.         "dirVideo": "/video"
  22.     }
  23. }
复制代码


控制器入口配置

在QQ物联开发配置平台,可以指定一个URL作为设备在手Q上的控制器。
配置步骤:
1, 访问并登录 http://iot.open.qq.com/
2, 开发配置平台 =》 在设备中点击一个设备 =》 控制面板 =》 自定义控制器 改成您的控制器URL。


目前局域网通信SDK有行车记录仪的应用场景,默认的控制器为:
http://qzs.qq.com/open/mobile/iot_tachograph/app/online/page/index.html
支持参数
  1. device=192.168.1.1  #指定设备IP,如果不指定设备IP,则使用手机当前的网关作为设备IP。
  2.     cgi=qqiot   #指定cgi处理路径,默认是qqiot,在uhttpd作为服务器时,需要指定为 cgi-bin/qqiot
  3.     port=3280   #指定设备提供的服务端口,默认是3280或者80
  4.     #示例:
  5.     http://qzs.qq.com/open/mobile/iot_tachograph/app/online/page/index.html?cgi=cgi-bin/qqiot&port=3280
复制代码


源码下载

下载

依赖库
依赖 libc
依赖 libgcc

注意问题
1, 建议使用配置文件记录设备的配置,示例见solution/qqiotws.conf, 参考device_init()对配置文件的处理
2, 错误:The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed
原因:solution/qqiot_config.h 中定义 #define ADD_ACCESS_CONTROL_ALLOW_ORIGIN,同时WEB服务器中加入了默认HTTP头Access-Control-Allow-Origin: * 导致重复的HTTP头,这种情况下会导致QQ连接不到设备。
3, 设置了照片文件夹/视频文件夹,但是获取设备信息得到的"dirPhoto"为空。
原因:为保证安全,所有的目录都应该在 defaultHome 之下,否则会被认为是没有权限
4, 错误:手Q连接正常,但是看不到文件。
可能是文件下载地址错误,solution/device_init.c提供的示例get_download_url_XSendfile() 只是配合nginx和特定的配置,您需要根据自己的设备配置实现文件下载URL的拼接
5, 在移植到Android系统时,如果未能自动生成NDK独立工具链,导致找不到编译器,请修改以下命令,并手动执行。
  1. /dir/to/Android/NDK/android-ndk-r10e.linux/build/tools/make-standalone-toolchain.sh --arch=arm \
  2.         --toolchain=arm-linux-androideabi-4.8 \
  3.         --platform=android-9 \
  4.         --install-dir="/tmp/arm_android.toolchain"
复制代码


联系我们

若开发者使用SDK遇到问题,可以在问题反馈系统中提交需求,QQ物联团队会排期进行处理。



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝4

帖子1145

发布主题
阅读排行 更多
广告位
关注官方微信

微信号:dean_green

微博:blueFresh素材大全

QQ1群:45163589

QQ2群:54765476

全国服务热线:

400-123-456789

(工作日:周一至周五 9:00-16:00)
北京市朝阳区红军营南路19号集美家居后院楼2层
enquire@dean_green.com

小黑屋-手机版- 我爱物联网(www.52iots.com)   

Powered by Discuz! X3.2© 2001-2013 Comsenz Inc.  豫ICP备12018881号