Toggle navigation
首页
(current)
问答
文章
话题
商城
登录
注册
10、RDA8910CSDK二次开发:简易的http通讯库
h't't'p
air724UG
RDA8910
socket
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) 本系列博客所述资料`均来自合宙官方`,并不是本人原创(只有博客是...
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) 本系列博客所述资料`均来自合宙官方`,并不是本人原创(只有博客是自己写的),csdk只是得到了`口头的允许公开授权`。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,`没有为自己谋取私利的想法`。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。 本系列博客基于紫光展锐的`RDA8910 LTE Cat 1` bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。 各个厂家的部分配置文件可能不一样,也许会导致设备出现奇怪的问题,其他的模块我也不确定能不能用,自行测试。但是有一点`编译下载和监视流程基本一样`,可供参考。 先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(`也有可能变砖,慎重!!!`)。 我使用的是`Air724UG`开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考! # 一、前言 有好几天没写博客了,几天前刚说了tcp通讯和udp通讯。本来准备写一下http协议怎么使用,在官方开发包里找了半天没找到有关http的库函数。后来通过其他渠道确认了官方暂时还`没有提供有关http的相关库`函数。也就是说除非自己写或者自己移植,不然就没法用。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200531165445606.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) 随后想了下,干脆移植一个开源库试试吧,也许运气好移植成功了呢。花了半天时间找了几个开源的http库,打开一看实在是太复杂了,以我的能力暂时是搞不定。看的我头晕眼花,果断放弃。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200531170622140.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) 其实我对这个库的要求也不高,支持以下简单的post,get。然后能下载稍大的文件就行了。如果有https那就更好了,没有也不碍事。既然移植不成那就自己写一个简单的吧,凑合用一下。过一段时间也许官方的库就出来了。 http说到底其实也就是一个tcp连接,发送指定的报文信息而已,简单的应用并不复杂。只要在网上找一个协议报文格式,对着的信息上面直接替换即可。 下面就是一个GET请求的报文格式,用的是`HTTP/1.1`协议,注意`HTTP/1.1`支持`长连接`,但是这个长连接并不是永久的长连接。`在短时间内`,可以允许客户端向服务器连续发送多个请求,而无需重新建立连接。在空闲时(`一段时间没有动作`)服务器会主动断开与客户端的连接。 ```c GET /admin_ui/rdx/core/images/close.png HTTP/1.1 Accept-Language: en-US User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E) Accept-Encoding: gzip, deflate Host: xxx.xxx.xxx.xxx Connection: Keep-Alive Accept: */* ``` # 二、编写测试程序 花了几天时间,根据报文的格式要求,写了一个简易的`http`函数库,目前只支持`GET`请求、`POST`请求。可以支持下载一些不是特别大的文件,昨晚测试下载800kb的文件没遇到什么问题。`https`暂时还没写,先凑合用着吧。 ## 2.1、了解本例程所用到的函数 至于内部怎么实现的我这里就不讲了,很简单,代码开源,有兴趣的可以自己去看。这里只介绍怎么使用库函数。 使用http服务需要包含`#include "http_client.h""`头文件,我们这里只用到了3个函数,分别是: >/**新建一个http的对象,每次调用都会新建一个独立的对象,不会修改原有的对象 >当初始化传入的参数不足时,初始化会失败,需要调用`http_get_init_state`,查询初始化状态 *@param config: 用户传入的初始化结构体 *@return 新建的http对象 **/ * http_client_handle_t `http_client_new`(http_client_config_t *config) > /**获取初始化的状态 *@param client:填写`http_client_new`返回的对象 *@return : 初始化的状态 **/ * http_client_init_state `http_get_init_state`(http_client_handle_t *client); > /**/根据新建的对象,执行相应的操作 *@param client:填写`http_client_new`返回的对象 **/ * void http_client_perform(http_client_handle_t *client); ## 2.2、编写get请求测试程序 demo中我写了两个get请求的测试,两个url只要选一个就行了,demo写的比较简单,一次只能测试一个请求。 ```c http_client_config_t config = {0}; //////////////GET测试1///////////////////////// config.url = "https://bkimg.cdn.bcebos.com/pic/37d3d539b6003af356370ff93f2ac65c1138b69e?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"; ////////////////////////////////////////////////// //////////////GET测试2///////////////////////// //config.url = "https://i0.hdslb.com/bfs/album/8ac5f3eecccb17dfe8702eff13a4fb51d59cfc4b.jpg"; config.method = HTTP_METHOD_GET; config.event_handler = http_cb; //创建对象 client_handle_t = http_client_new(&config); iot_debug_print("[http_client] init_state:%d", http_get_init_state(&client_handle_t)); if (http_get_init_state(&client_handle_t) == HTTP_INIT_OK) { http_client_perform(&client_handle_t); } ``` ## 2.3、编写post请求测试程序 post请求主要是提交数据,我这里向`http://httpbin.org/post`提交字符串`”123456“`,该网站会回应相应的的报文数据。 ```c ///////////////////POST测试//////////////////////// config.url = "http://httpbin.org/post"; config.table_data = "123456"; config.method = HTTP_METHOD_POST; //////////////////////////////////// config.event_handler = http_cb; //创建对象 client_handle_t = http_client_new(&config); iot_debug_print("[http_client] init_state:%d", http_get_init_state(&client_handle_t)); if (http_get_init_state(&client_handle_t) == HTTP_INIT_OK) { http_client_perform(&client_handle_t); } ``` ## 2.4、编写消息回调事件 函数库中做了分包接收(一个请求分多包接收),分段接收(一个文件多次请求,不需要用户处理,库函数全部处理好了,用户只需要在回调函数中转存数据即可)。只会在一次的请求数据全部接收到后才会通知消息处理函数。拿下载文件来说,一个文件可能有好几兆,我在库里面默认设置接收缓存区为10240字节(10KB),用户可以自行更改,一次最多接收10KB的数据。由于网络问题,这10KB的数据可能需要进行分包接收,回调函数只会在10KB的数据全部接收完毕后才会通过回调函数通知用户,转存数据。 ```c void http_cb(http_client_event *evt) { iot_os_sleep(1000);//这里需要一个延时,不然下载的过程中,打印速度太快,日志会丢失,不需要查看日志的话可以忽略 iot_debug_print("[http_client] http_client_event_state:%d", evt->state); iot_debug_print("[http_client] respons_state:%s", evt->respons_state); iot_debug_print("[http_client] data:%s", evt->data); iot_debug_print("[http_client] datalen:%d", evt->datalen); } ``` # 三、编译并下载程序 完整代码在这,自取。 ```c /* * @Author: your name * @Date: 2020-05-19 14:05:32 * @LastEditTime: 2020-05-31 17:53:31 * @LastEditors: Please set LastEditors * @Description: In User Settings Edit * @FilePath: \RDA8910_CSDK\USER\user_main.c */ #include "string.h" #include "cs_types.h" #include "osi_log.h" #include "osi_api.h" #include "am_openat.h" #include "am_openat_vat.h" #include "am_openat_common.h" #include "iot_debug.h" #include "iot_uart.h" #include "iot_os.h" #include "iot_gpio.h" #include "iot_pmd.h" #include "iot_adc.h" #include "iot_vat.h" #include "iot_network.h" #include "iot_socket.h" #include "http_client.h" HANDLE TestTask_HANDLE = NULL; uint8 NetWorkCbMessage = 0; int socketfd = -1; http_client_handle_t client_handle_t = {0}; void http_cb(http_client_event *evt) { iot_os_sleep(1000);//这里需要一个延时,不然下载的过程中,打印速度太快,日志会丢失,不需要查看日志的话可以忽略 iot_debug_print("[http_client] http_client_event_state:%d", evt->state); iot_debug_print("[http_client] respons_state:%s", evt->respons_state); iot_debug_print("[http_client] data:%s", evt->data); iot_debug_print("[http_client] datalen:%d", evt->datalen); } static void TestTask(void *param) { bool NetLink = FALSE; while (NetLink == FALSE) { T_OPENAT_NETWORK_CONNECT networkparam = {0}; switch (NetWorkCbMessage) { case OPENAT_NETWORK_DISCONNECT: //网络断开 表示GPRS网络不可用澹,无法进行数据连接,有可能可以打电话 iot_debug_print("[socket] OPENAT_NETWORK_DISCONNECT"); iot_os_sleep(10000); break; case OPENAT_NETWORK_READY: //网络已连接 表示GPRS网络可用,可以进行链路激活 iot_debug_print("[socket] OPENAT_NETWORK_READY"); memcpy(networkparam.apn, "CMNET", strlen("CMNET")); //建立网络连接,实际为pdp激活流程 iot_network_connect(&networkparam); iot_os_sleep(500); break; case OPENAT_NETWORK_LINKED: //链路已经激活 PDP已经激活,可以通过socket接口建立数据连接 iot_debug_print("[socket] OPENAT_NETWORK_LINKED"); NetLink = TRUE; break; } } if (NetLink == TRUE) { http_client_config_t config = {0}; //////////////GET测试1///////////////////////// config.url = "https://bkimg.cdn.bcebos.com/pic/37d3d539b6003af356370ff93f2ac65c1138b69e?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg"; config.method = HTTP_METHOD_GET; ////////////////////////////////////////////////// //////////////GET测试2///////////////////////// //config.url = "https://i0.hdslb.com/bfs/album/8ac5f3eecccb17dfe8702eff13a4fb51d59cfc4b.jpg"; //config.method = HTTP_METHOD_GET; ////////////////////////////////////////////////// ///////////////////POST测试//////////////////////// //config.url = "http://httpbin.org/post"; //config.table_data = "123456"; //config.method = HTTP_METHOD_POST; //////////////////////////////////// config.event_handler = http_cb; //创建对象 client_handle_t = http_client_new(&config); iot_debug_print("[http_client] init_state:%d", http_get_init_state(&client_handle_t)); if (http_get_init_state(&client_handle_t) == HTTP_INIT_OK) { http_client_perform(&client_handle_t); } } iot_os_delete_task(TestTask_HANDLE); } static void NetWorkCb(E_OPENAT_NETWORK_STATE state) { NetWorkCbMessage = state; } //main函数 int appimg_enter(void *param) { //系统休眠 iot_os_sleep(10000); //注册网络状态回调函数 iot_network_set_cb(NetWorkCb); //创建一个任务 //TestTask_HANDLE = TestTask_HANDLE = iot_os_create_task(TestTask, NULL, 2048, 10, OPENAT_OS_CREATE_DEFAULT, "TestTask"); return 0; } //退出提示 void appimg_exit(void) { OSI_LOGI(0, "application image exit"); } ``` # 四、分析结果 测试GET请求,通过打印数据,看到`Range_all`=25644字节,也就是图片的总大小25.6KB。分三段接收,第一段接收`10240`,第二段接收`10240`,第三段接收`5164`,三段加在一起正好是`25644`。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200531175821223.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) 测试POST请求,通过打印数据,http响应`200`,只能看到部分接收到的数据,还有数据大小是`495`字节。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200531190242442.png) 这时候我们需要用一下网络调试助手,将下面的数据发送出去,响应头中附带的信息是响应`200`,`Content-Length=496`,以及正文数据的第一行和我们在日志中看到的是一样的。数据应该是没什么问题,我也懒得将数据一行行拆开打印了测试了。 ```c POST /post HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36\r\nContent-Length: 8\r\nContent-Type: application/json\r\nAccept: */*\r\n\r\n123456\r\n ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200531190505375.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) # 五、总结 本人提供的函数包内,有如下接口可供使用。 ```c //修改host数据,必须先创建一个client对象才可以修改 void http_set_host(http_client_handle_t *client, char *host); //获取host数据 char *http_get_host(http_client_handle_t *client); //修改ip数据,必须先创建一个client对象才可以修改 void http_set_ip(http_client_handle_t *client, char *ip); //获取ip数据 char *http_get_ip(http_client_handle_t *client); //修改port数据,必须先创建一个client对象才可以修改 void http_set_port(http_client_handle_t *client, int port); //获取port数据 int http_get_port(http_client_handle_t *client); //修改path数据,必须先创建一个client对象才可以修改 void http_set_path(http_client_handle_t *client, char *path); //获取path数据 char *http_get_path(http_client_handle_t *client); //修改table_data数据,必须先创建一个client对象才可以修改 void http_set_table_data(http_client_handle_t *client, char *table_data); //获取table_data数据 char *http_get_table_data(http_client_handle_t *client); //修改method数据,必须先创建一个client对象才可以修改 void http_set_method(http_client_handle_t *client, http_client_method_t method); //获取method数据 http_client_method_t http_get_method(http_client_handle_t *client); //修改event_handler数据,必须先创建一个client对象才可以修改 void http_set_event_handler(http_client_handle_t *client, http_event_handle_cb event_handler); //删除http对象 void http_delete(http_client_handle_t *client); //获取初始化状态 http_client_init_state http_get_init_state(http_client_handle_t *client); //新建一个http的对象 http_client_handle_t http_client_new(http_client_config_t *config); //根据新建的对象,执行相应的操作 void http_client_perform(http_client_handle_t *client); ``` 一般情况下只需要用到如下4个函数即可满足简单的使用需求。复杂的功能我也没写,其他的接口主要是修改http对象内部变量的值,也可以直接通过指针修改(`不推荐`),容易出现问题。 ```c //删除http对象 void http_delete(http_client_handle_t *client); //获取初始化状态 http_client_init_state http_get_init_state(http_client_handle_t *client); //新建一个http的对象 http_client_handle_t http_client_new(http_client_config_t *config); //根据新建的对象,执行相应的操作 void http_client_perform(http_client_handle_t *client); ``` > 不会下载的[点击这里](https://blog.csdn.net/weixin_44570083/article/details/104285283),进去查看我的`RDA8910 CSDK二次开发入门教程`专题第一篇博文`1、RDA8910CSDK二次开发:环境搭建`里面讲了怎么下载 > 这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束
发表于 2020-05-31 19:21
阅读 ( 1913 )
2 推荐
收藏
你可能感兴趣的文章
13、RDA8910CSDK二次开发:将你的代码藏起来----编译静态库
5552 浏览
1.1、RDA8910CSDK二次开发:CSDK极致开发体验
7886 浏览
12、RDA8910CSDK二次开发:c语言中最好用的JSON解析库---cJSON
6180 浏览
11、RDA8910CSDK二次开发:新鲜出炉的MQTT库
8003 浏览
9、RDA8910CSDK二次开发:趁热打铁干脆顺带把UDP通讯也给撸了吧
1947 浏览
相关问题
2G模块连接阿里云每隔3s上发一次数据,但是会报错出现连接重置,日志打出来是ssl连接被关闭,请问这是信号差的原因还是什么其他的原因?
0 回答
EVB_Air720UG_A12测试sdcard失败
0 回答
AIR724UG 固件下载失败
2 回答
合宙Air724UG的USB驱动问题
1 回答
0 条评论
请先
登录
后评论
陈夏
26 篇文章
作家榜
»
技术销售Delectate
43 文章
陈夏
26 文章
国梁
24 文章
miuser
21 文章
晨旭
20 文章
朱天华
19 文章
金艺
19 文章
杨奉武
18 文章
×
发送私信
发给:
内容:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!