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

cnblogs 2024-06-12 08:15:00 阅读 51

利用HTTP协议向聚合数据API发送请求,并利用cJSON库对服务器返回的JSON格式数据完成解析

目录

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

题目


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

注意事项

1.预测的日期开始时间为2010-01-01

2."老黄历"API 服务器返回值是将响应包体与响应行一同返回,所以该程序只需要对服务器返回值接收一次,再利用strstr进行找寻响应包体,最后完成JASON格式数据的解析,但是,这种返回方式不是固定的。例如:“天气预报”API返回数据将响应行与响应包体分为两次发出,所以需要接收两次。

3.该程序代码使用了cJSON库,所以需要用户提前下载并将cJSON.c和cJSON.h加入程序文档。

实现代码

/********************************************************************************

*

*file name:demo.c

*author : ProgramMonkey_Fly@126.com

*date : 2024/06/11

*function :

* 该案例是学习掌握对JSON格式服务器响应数据的解析与构造

*使用“聚合数据”官网提供的免费接口“老黄历”作为学习例子

* note :

*1.预测的日期开始时间为2010-01-01

*2."老黄历"API 服务器返回值是将响应包体与响应行一同返回,所以该程序只需要

*对服务器返回值接收一次,再利用strstr进行找寻响应包体,最后完成JASON

*格式数据的解析,但是,这种返回方式不是固定的。例如:“天气预报”API返回

*数据将响应行与响应包体分为两次发出,所以需要接收两次。

*3.该程序代码使用了cJSON库,所以需要用户提前下载并将cJSON.c和cJSON.h加入

*程序文档。

* version :

*

*CopyRight (c) 2023-2024 ProgramMonkey_Fly@126.com All Right Reseverd

*

* ******************************************************************************/

/****************************头文件*********************************************/

#include <sys/socket.h>

#include <sys/types.h>

#include <time.h>

#include <errno.h>

#include <signal.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/wait.h>

#include <sys/time.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <stdio.h>

#include <sys/select.h>

#include "cJSON.h"

#include <string.h>

/****************************宏定义*********************************************/

#define HOST "v.juhe.cn" //服务器域名

#define PORT 80 //http协议端口号

#define BUFSIZE 4096 //自定义缓冲区大小

#define KEY "..." //API需要的密钥(在个人中心->我的数据,接口名称上方查看)

#define DATE "2024-06-12" //想要预测日期,格式2014-09-09

int main(int argc, char **argv)

{

//创建TCP的套接字文件

int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

if(tcp_socket == -1)

{

fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));

exit(1);

}

//向服务器发送请求之前,需要设置目标端口和目标地址

struct sockaddr_in dest_addr;

socklen_t flag_dest = sizeof(dest_addr);

dest_addr.sin_family = AF_INET; //协议族,是固定的

dest_addr.sin_port = htons(PORT);//服务器运行进程的端口号,必须转换为网络字节序

//利用gethostbyname函数接口,获取服务器域名所包含的信息---即获取服务器的ip

struct hostent *hostent = gethostbyname(HOST);

if(hostent == NULL)

{

fprintf(stderr, "ip get error,errno:%d,%s\n",errno,strerror(errno));

exit(2);

}

//存储服务器IP地址,必须转换为点分十进制字符串形式

dest_addr.sin_addr.s_addr = inet_addr("203.107.54.210");

//使用connect函数接口向服务器发起连接申请

int flag_connect = connect(tcp_socket, (struct sockaddr *)&dest_addr, flag_dest);

if(flag_connect == -1)

{

fprintf(stderr, "connect socket error,errno:%d,%s\n",errno,strerror(errno));

exit(3);

}

//连接成功后,向服务器发送请求

char buf[BUFSIZE] = {0};

sprintf(buf, "POST http://v.juhe.cn/laohuangli/d?key=%s&date=%s HTTP/1.1\r\n"

"HOST: %s\r\n"

"Content-Type: application/x-www-form-urlencoded\r\n"

"\r\n"

,KEY

,DATE

,HOST);

int ret = write(tcp_socket,buf,strlen(buf));

if (ret < 0)

{

fprintf(stderr,"send data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));

exit(4);

}

else

{

printf("send data success, length:%d byte!\n\n", ret);

}

//利用select监测套接字状态,当服务器发送数据时,进行接收操作

fd_set t_set1;

struct timeval tv;

//清零集合,并设置超时为五秒钟

FD_ZERO(&t_set1);

tv.tv_usec = 0;//微秒为单位

tv.tv_sec = 5;//设置等待时间为五秒

// 执行“少量多次”的规则,监测套接字状态

while(1)

{

//把套接字加入集合中

FD_SET(tcp_socket, &t_set1);

int flag_slect = select(tcp_socket + 1, &t_set1, NULL, NULL, &tv);

printf("flag_slect = %d\n",flag_slect);

//检测集合读状态失败

if(flag_slect < 0)

{

close(tcp_socket);//关闭套接字

fprintf(stderr,"read data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));

exit(5);

}

//超时则重新监测

if(flag_slect == 0)

{

printf("h:%d sec:%ld usec:%ld\n\n", flag_slect, tv.tv_sec, tv.tv_usec);

continue;

}

//服务器已经发送数据,可以执行读取操作

if(flag_slect > 0)

{

memset(buf, 0, BUFSIZE);

int i = read(tcp_socket, buf, BUFSIZE);

printf("%s\n", buf);

if (i == 0)

{

close(tcp_socket);//关闭套接字

fprintf(stderr,"read data fail! errno:%d, errmsg:'%s'\n\n",errno, strerror(errno));

exit(6);

}

break;

}

}

//对读取到的数据进行处理,由于响应包体跟响应行+响应字段粘合在一起,所以需要先对获取数据作初步处理

char *buf1 = strstr(buf, "{");

// 1. 将存储JSON格式的字符串转换成JASON格式数据

cJSON *json = cJSON_Parse(buf1);

//2. 对转换后的数据进行输出调试

char *string = cJSON_Print(json);

printf("%s\n", string);

//3. 练习:利用cJSON_GetObjectItem获取指定键名的值

cJSON *result = cJSON_GetObjectItem(json, "result");

cJSON *jishen = cJSON_GetObjectItem(result, "jishen");

char *str_jishen = cJSON_Print(jishen);

printf("吉神宜趋: %s\n", str_jishen);

//关闭套接字

close(tcp_socket);

return 0;

}

结果展示

image

相关接口指引

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


声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。