目錄題目註意事項實現代碼結果展示相關介面指引 題目 利用某些平臺(聚合API、百度AI、科大訊飛API)的API介面,利用HTTP協議向伺服器發送請求,並接受伺服器的響應,要求利用cJSON庫對伺服器的響應數據進行解析,並輸出到終端。 註意事項 1.預測的日期開始時間為2010-01-01 2."老 ...
目錄
題目
利用某些平臺(聚合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 : [email protected]
* 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 [email protected] 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;
}
結果展示
相關介面指引
- 一般嵌入式開發中可以使用cJSON庫對JSON格式進行解析,cJSON庫是基於C語言的一個開源項目,github下載地址:https://github.com/DaveGamble/cJSON
- 免費API介面工具大全 - 聚合數據 (juhe.cn)