找回密码
 立即注册
首页 业界区 安全 网络编程练习题---利用cJSON库对服务器返回的JSON格式数 ...

网络编程练习题---利用cJSON库对服务器返回的JSON格式数据完成解析

懵径 昨天 09:40
目录

  • 题目

    • 注意事项
    • 实现代码
    • 结果展示
    • 相关接口指引


题目

利用某些平台(聚合API、百度AI、科大讯飞API)的API接口,利用HTTP协议向服务器发送请求,并接受服务器的响应,要求利用cJSON库对服务器的响应数据进行解析,并输出到终端。
注意事项

1.预测的日期开始时间为2010-01-01
2."老黄历"API 服务器返回值是将响应包体与响应行一同返回,所以该程序只需要对服务器返回值接收一次,再利用strstr进行找寻响应包体,最后完成JASON格式数据的解析,但是,这种返回方式不是固定的。例如:“天气预报”API返回数据将响应行与响应包体分为两次发出,所以需要接收两次。
3.该程序代码使用了cJSON库,所以需要用户提前下载并将cJSON.c和cJSON.h加入程序文档。
实现代码
  1. /********************************************************************************
  2. *
  3. *        file name:        demo.c
  4. *        author         :  ProgramMonkey_Fly@126.com
  5. *        date         :  2024/06/11
  6. *        function :  
  7. *               该案例是学习掌握对JSON格式服务器响应数据的解析与构造
  8. *                                使用“聚合数据”官网提供的免费接口“老黄历”作为学习例子
  9. *         note         :  
  10. *                                1.预测的日期开始时间为2010-01-01
  11. *                                2."老黄历"API 服务器返回值是将响应包体与响应行一同返回,所以该程序只需要
  12. *                                        对服务器返回值接收一次,再利用strstr进行找寻响应包体,最后完成JASON
  13. *                                        格式数据的解析,但是,这种返回方式不是固定的。例如:“天气预报”API返回
  14. *                                        数据将响应行与响应包体分为两次发出,所以需要接收两次。
  15. *                                3.该程序代码使用了cJSON库,所以需要用户提前下载并将cJSON.c和cJSON.h加入
  16. *                                        程序文档。
  17. *   version  :
  18. *
  19. *        CopyRight (c)  2023-2024   ProgramMonkey_Fly@126.com   All Right Reseverd
  20. *
  21. * ******************************************************************************/
  22. /****************************头文件*********************************************/
  23. #include <sys/socket.h>
  24. #include <sys/types.h>
  25. #include <time.h>
  26. #include <errno.h>
  27. #include <signal.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #include <sys/wait.h>
  32. #include <sys/time.h>
  33. #include <netinet/in.h>
  34. #include
  35. #include <netdb.h>
  36. #include <stdio.h>
  37. #include <sys/select.h>
  38. #include "cJSON.h"
  39. #include <string.h>
  40. /****************************宏定义*********************************************/
  41. #define HOST "v.juhe.cn"                                                        //服务器域名
  42. #define PORT 80                                                                 //http协议端口号
  43. #define BUFSIZE 4096                                                             //自定义缓冲区大小
  44. #define KEY  "..."                                                                                   //API需要的密钥(在个人中心->我的数据,接口名称上方查看)
  45. #define DATE "2024-06-12"                                                                  //想要预测日期,格式2014-09-09
  46. int main(int argc, char **argv)
  47. {
  48.     //创建TCP的套接字文件
  49.         int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
  50.         if(tcp_socket == -1)
  51.         {
  52.                 fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
  53.                 exit(1);
  54.         }
  55.         //向服务器发送请求之前,需要设置目标端口和目标地址
  56.         struct sockaddr_in  dest_addr;
  57.         socklen_t flag_dest = sizeof(dest_addr);
  58.         dest_addr.sin_family                 = AF_INET;                                                 //协议族,是固定的
  59.         dest_addr.sin_port                   = htons(PORT);                        //服务器运行进程的端口号,必须转换为网络字节序
  60.         //利用gethostbyname函数接口,获取服务器域名所包含的信息---即获取服务器的ip
  61.     struct hostent *hostent =  gethostbyname(HOST);
  62.         if(hostent == NULL)
  63.         {
  64.                 fprintf(stderr, "ip get error,errno:%d,%s\n",errno,strerror(errno));
  65.                 exit(2);
  66.         }
  67.         //存储服务器IP地址,必须转换为点分十进制字符串形式
  68.         dest_addr.sin_addr.s_addr   = inet_addr("203.107.54.210");               
  69.         //使用connect函数接口向服务器发起连接申请
  70.         int flag_connect = connect(tcp_socket, (struct sockaddr *)&dest_addr, flag_dest);
  71.         if(flag_connect == -1)
  72.         {
  73.                 fprintf(stderr, "connect socket error,errno:%d,%s\n",errno,strerror(errno));
  74.                 exit(3);
  75.         }
  76.         //连接成功后,向服务器发送请求
  77.         char buf[BUFSIZE] = {0};
  78.         sprintf(buf, "POST http://v.juhe.cn/laohuangli/d?key=%s&date=%s HTTP/1.1\r\n"
  79.                                 "HOST: %s\r\n"
  80.                                 "Content-Type: application/x-www-form-urlencoded\r\n"
  81.                                 "\r\n"
  82.                                 ,KEY
  83.                                 ,DATE
  84.                                 ,HOST);
  85.         int ret = write(tcp_socket,buf,strlen(buf));
  86.     if (ret < 0)
  87.         {
  88.         fprintf(stderr,"send data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));
  89.         exit(4);
  90.     }
  91.         else
  92.         {
  93.         printf("send data success, length:%d byte!\n\n", ret);
  94.     }
  95.         //利用select监测套接字状态,当服务器发送数据时,进行接收操作
  96.         fd_set t_set1;
  97.         struct timeval tv;
  98.         //清零集合,并设置超时为五秒钟
  99.         FD_ZERO(&t_set1);
  100.         tv.tv_usec = 0;                        //微秒为单位
  101.         tv.tv_sec = 5;                        //设置等待时间为五秒
  102.         // 执行“少量多次”的规则,监测套接字状态
  103.         while(1)
  104.         {
  105.                 //把套接字加入集合中
  106.                 FD_SET(tcp_socket, &t_set1);
  107.                 int flag_slect = select(tcp_socket + 1, &t_set1, NULL, NULL, &tv);
  108.                 printf("flag_slect = %d\n",flag_slect);
  109.                 //检测集合读状态失败
  110.                 if(flag_slect < 0)
  111.                 {
  112.                         close(tcp_socket);//关闭套接字
  113.                         fprintf(stderr,"read data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));
  114.             exit(5);
  115.                 }
  116.                 //超时则重新监测
  117.                 if(flag_slect == 0)
  118.                 {
  119.                         printf("h:%d sec:%ld usec:%ld\n\n", flag_slect, tv.tv_sec, tv.tv_usec);
  120.                         continue;
  121.                 }
  122.                 //服务器已经发送数据,可以执行读取操作
  123.                 if(flag_slect > 0)
  124.                 {
  125.                         memset(buf, 0, BUFSIZE);
  126.             int i = read(tcp_socket, buf, BUFSIZE);
  127.                         printf("%s\n", buf);
  128.                         if (i == 0)
  129.                         {
  130.                 close(tcp_socket);//关闭套接字
  131.                 fprintf(stderr,"read data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));
  132.                 exit(6);
  133.             }
  134.                         break;
  135.                 }
  136.         }
  137.         //对读取到的数据进行处理,由于响应包体跟响应行+响应字段粘合在一起,所以需要先对获取数据作初步处理
  138.         char *buf1 = strstr(buf, "{");
  139.         // 1. 将存储JSON格式的字符串转换成JASON格式数据
  140.         cJSON *json = cJSON_Parse(buf1);
  141.         //2. 对转换后的数据进行输出调试
  142.         char *string = cJSON_Print(json);
  143.         printf("%s\n", string);
  144.         //3. 练习:利用cJSON_GetObjectItem获取指定键名的值
  145.         cJSON *result = cJSON_GetObjectItem(json, "result");
  146.         cJSON *jishen = cJSON_GetObjectItem(result, "jishen");
  147.         char *str_jishen = cJSON_Print(jishen);
  148.         printf("吉神宜趋: %s\n", str_jishen);
  149.         //关闭套接字
  150.         close(tcp_socket);
  151.         return 0;
  152. }
复制代码
结果展示

1.png

相关接口指引


  • 一般嵌入式开发中可以使用cJSON库对JSON格式进行解析,cJSON库是基于C语言的一个开源项目,github下载地址:https://github.com/DaveGamble/cJSON
  • 免费API接口工具大全 - 聚合数据 (juhe.cn)

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册