Linux网络编程应用:教你如何从阿里云获取天气数据、快递物流数据(HTTP协议、C语言)

一、获取天气数据

准备工作

一、点击阿里云链接阿里云,搜索易源天气,找到下方的购买调试入口:(其他天气也可以,请求参数可能有不同)
在这里插入图片描述
2、登录后点击购买,新用户不用花钱,但是只能访问100次。
在这里插入图片描述
三、购买后找到购买界面下面有一个调试,或者到自己的管理控制台找到已购买的API:
在这里插入图片描述
四、进入调试界面,输入区域名字,点击发送请求,可以接收到返回信息,说明调试成功,记录下图红圈中的重要参数,要写到代码。
在这里插入图片描述

五、下载cJOSN:cJOSN下载链接
这是我下载好的cJOSN源码,本教程只需要用到cJOSN.c与cJOSN.h
在这里插入图片描述
到这准备工作就做完了。

相关知识点

HTTP请求报文格式(注意空格与换行符):

GET /spot-to-weather?area=广州 HTTP/1.1\r\n
Host: weather01.market.alicloudapi.com\r\n
Authorization:APPCODE xxxxxxxxxxx

在这里插入图片描述
C语言请求数据代码例程:

//获取请求数据
//Authorization需要到网上自己购买
char *httpRequest(const char *host)
{
    
    
    static char request[1024];
	snprintf(request, 1024, "GET /spot-to-weather?area=广州 HTTP/1.1\r\n"
                            "Host: weather01.market.alicloudapi.com\r\n"
                            "Authorization: APPCODE xxxxxxxx\r\n"
                            "\r\n", host);
    return request;
}

HTTP响应报文格式

发送请求后http会返回数据,格式如下:

在这里插入图片描述
http返回的数据:
数据头

HTTP/1.1 200 OK Date: Thu, 10 Sep 2020 07:06:10 GMT Content-Type:
application/json;charset=utf-8 Content-Length: 2708 Connection:
keep-alive Keep-Alive: timeout=25 Vary: Accept-Encoding
Access-Control-Allow-Headers: * Server: openresty showapi_fee_num: 1
X-Ca-Request-Id: 24BBCE93-5192-4A51-8522-8EFFBDE6C5B1
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Max-Age: 1728000

数据本文(josn格式)

{
“showapi_res_error”: “”,
“showapi_res_id”: “5f59d0628d57ba481d3fa586”,
“showapi_res_code”: 0,
“showapi_res_body”: {“time”:“20200910120000”,“ret_code”:0,“now”:{“weather_code”:“01”,“aqiDetail”:{“co”:“0.6”,“num”:“231”,“so2”:“11”,“area”:“广州”,“o3”:“104”,“no2”:“25”,“aqi”:“44”,“quality”:“优质”,“pm10”:“44”,“pm2_5”:“25”,“o3_8h”:“91”,“primary_pollutant”:“O3”},“wind_direction”:“西南风”,“temperature_time”:“15:00”,“wind_power”:“1级”,“aqi”:“44”,“sd”:“59%”,“weather_pic”:“http://app1.showapi.com/weather/icon/day/01.png”,“weather”:“多云”,“temperature”:“33”},“cityInfo”:{“c6”:“guangdong”,“c5”:“广州”,“c4”:“guangzhou”,“c3”:“越秀”,“c9”:“中国”,“c8”:“china”,“c7”:“广东”,“c17”:"+8",“c16”:“AZ9200”,“c1”:“101280107”,“c2”:“yuexiu”,“c0”:“440104”,“longitude”:113.261,“c11”:“020”,“c10”:“3”,“latitude”:23.131,“c12”:“510000”,“c15”:“28”},“showapi_fee_code”:-1,“f1”:{“night_weather_code”:“04”,“day_weather”:“雷阵雨”,“night_weather”:“雷阵雨”,“jiangshui”:“85%”,“air_press”:“1007
hPa”,“night_wind_power”:“0-3级 <5.4m/s”,“day_wind_power”:“0-3级
<5.4m/s”,“day_weather_code”:“04”,“sun_begin_end”:“06:11|18:36”,“ziwaixian”:“最弱”,“day_weather_pic”:“http://app1.showapi.com/weather/icon/day/04.png”,“weekday”:4,“night_air_temperature”:“26”,“day_wind_direction”:“无持续风向”,“day_air_temperature”:“33”,“night_wind_direction”:“无持续风向”,“night_weather_pic”:“http://app1.showapi.com/weather/icon/night/04.png”,“day”:“20200910”},“f3”:{“night_weather_code”:“04”,“day_weather”:“中雨”,“night_weather”:“雷阵雨”,“jiangshui”:“84%”,“air_press”:“1007
hPa”,“night_wind_power”:“0-3级 <5.4m/s”,“day_wind_power”:“0-3级
<5.4m/s”,“day_weather_code”:“08”,“sun_begin_end”:“06:12|18:34”,“ziwaixian”:“最弱”,“day_weather_pic”:“http://app1.showapi.com/weather/icon/day/08.png”,“weekday”:6,“night_air_temperature”:“25”,“day_wind_direction”:“无持续风向”,“day_air_temperature”:“30”,“night_wind_direction”:“无持续风向”,“night_weather_pic”:“http://app1.showapi.com/weather/icon/night/04.png”,“day”:“20200912”},“f2”:{“night_weather_code”:“09”,“day_weather”:“雷阵雨”,“night_weather”:“大雨”,“jiangshui”:“82%”,“air_press”:“1007
hPa”,“night_wind_power”:“0-3级 <5.4m/s”,“day_wind_power”:“0-3级
<5.4m/s”,“day_weather_code”:“04”,“sun_begin_end”:“06:11|18:35”,“ziwaixian”:“最弱”,“day_weather_pic”:“http://app1.showapi.com/weather/icon/day/04.png”,“weekday”:5,“night_air_temperature”:“25”,“day_air_temperature”:“33”,“day_wind_direction”:“无持续风向”,“day”:“20200911”,“night_weather_pic”:“http://app1.showapi.com/weather/icon/night/09.png”,“night_wind_direction”:“无持续风向”}}
}

而有用的数据就是除了头部分的文本数据,这些数据是一个大数组,想要提取其中的某些数据显然有些困难。于是利用刚刚下载好的cJOSN 源码,利用其中的函数来解析这一堆杂乱的数据。

代码工程建立

一、把cJOSN.c与cJOSN.h 、你的主程序 拷贝到ubuntu 目录下:
在这里插入图片描述
二、编写代码(注意xxxxxxxx需要使用自己购买的APPCODE 编码,在调试信息可以看到)

/*************************************
* 数据来源:阿里云-易源天气
* 获取天气的网址:weather01.market.alicloudapi.com
****************************************/
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "cJSON.h"

#define SERV_PORT 80

//出错
void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}

//获取请求数据
//Authorization需要到网上自己购买,首次不收费 0.01元连接100次
char *httpRequest(const char *host)
{
    
    
    static char request[1024];
	snprintf(request, 1024, "GET /spot-to-weather?area=广州 HTTP/1.1\r\n"
                            "Host: %s\r\n"
                            "Authorization: APPCODE xxxxxxxx\r\n"
                            "\r\n", host);
    return request;
}

int main(int argc, const char **argv)
{
    
    
	if(argc != 2)
	{
    
    
		printf("input error: try ‘./client weather01.market.alicloudapi.com’\n");
		exit(0);
	}
	cJSON *js=NULL;//JOSN解析结构体
	cJSON *item=NULL;
	cJSON *wer_item=NULL;
	
	int lfd,cfd;	//套接字
	char buf[100*1024],j_buf[1024*100];//接收数组
	
	struct hostent *ht = gethostbyname(argv[1]);//根据域名获得IP
	if(ht == NULL){
    
    
		perror("gethostbyname");
		exit(0);
	}

    sprintf(buf,"%s", inet_ntoa(*((struct in_addr *)(ht->h_addr_list)[0])));
	printf("解析IP:%s\n",buf);
	
	struct sockaddr_in serv_addr;          //服务器地址结构
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    //inet_pton(AF_INET, buf, &serv_addr.sin_addr); //两种方法赋值
	serv_addr.sin_addr = *((struct in_addr *)(ht->h_addr_list[0]));
	
	lfd = socket(AF_INET, SOCK_STREAM, 0);//新建网络套接字
    if (lfd == -1)
        sys_err("socket error");
	
	printf("尝试连接...\n");//尝试连接网络地址
    int ret = connect(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (ret != 0)
        sys_err("connect err");
	printf("已连接到:%s\n",argv[1]);
	
	char *s = httpRequest(argv[1]);//获取请求数组
	
	printf("发送请求:%s\n",s);
	write(lfd,s,strlen(s)); //发送请求
	
	
	read(lfd,buf,sizeof(buf));//获取数据
	//printf("收到报文:%s\n",buf);

	/***砍去头部,不然解析会出错****/
	int j=0,flag=0;
	for(int i=0; i<strlen(buf)+1; i++)
	{
    
    
		if(buf[i] == '{' || flag == 1){
    
    
			flag = 1;
			j_buf[j] = buf[i];
			j++;
		}
	}//printf("砍头后的数据:%s\n",j_buf);
	
	
	//printf("解析JOSN数据..\n");
	js = cJSON_Parse(j_buf); //把去头的报文JOSN进行解析
	//printf("%s\n",cJSON_Print(js));//打印解析好的报文数据


	/*获取指定数据 层层查找法,要查看JOSN结构名称*/
	//printf("指定数据获取:\n\n");
	item = cJSON_GetObjectItem(js, "showapi_res_body");
	printf("时间:%s\n",cJSON_GetObjectItem(item, "time")->valuestring);
	item = cJSON_GetObjectItem(item, "now");
	wer_item = cJSON_GetObjectItem(item, "aqiDetail");
	//地名查看
	wer_item = cJSON_GetObjectItem(wer_item, "area");
    if(wer_item != NULL){
    
    
        printf("地区:%s\n",wer_item->valuestring);
    }
	//天气查看
	wer_item = cJSON_GetObjectItem(item, "weather");
    if(wer_item != NULL){
    
    
        printf("天气:%s\n",wer_item->valuestring);
    }
	//温度查看
	wer_item = cJSON_GetObjectItem(item, "temperature");
    if(wer_item != NULL){
    
    
        printf("温度: %s℃\n",wer_item->valuestring);
    }
	//风向查看
	wer_item = cJSON_GetObjectItem(item, "wind_direction");
    if(wer_item != NULL){
    
    
        printf("风向:%s\n",wer_item->valuestring);
    }
	
    //将json结构占用的数据空间释放
    cJSON_Delete(js);
	//关闭连接
	close(lfd);

	return 0;
}

三、编译:

#gcc cJSON.c client.c -o client

在这里插入图片描述
四、运行:
运行结果:

time:20200911180000
area:广州
weather:阴
temperature: 29℃
wind_direction:东风

在这里插入图片描述

取消代码中的打印注释可以看到详细返回,解析数据:
在这里插入图片描述

二、获取物流信息

根据获取天气同样操作可以获取物流信息
我用的是这个:
在这里插入图片描述

获取物流信息代码:

/*************************************
* 数据来源:阿里云-全国快递单号查询
* 获取物流的网址:jisukdcx.market.alicloudapi.com
****************************************/
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "cJSON.h"

#define SERV_PORT 80
#define INET "jisukdcx.market.alicloudapi.com"

//出错
void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}

//获取请求数据
//Authorization需要到网上自己购买
char *httpRequest(const char *number,const char *type,const char *host)
{
    
    
    static char request[1024];
	snprintf(request, 1024, "GET /express/query?" 		//路径
							"number=%s&" 	//参数
							"type=%s "
							"HTTP/1.1\r\n"
                            "Host: %s\r\n"
                            "Authorization:APPCODE XXXXXXXXX\r\n"
                            "\r\n",number, type, host);
    return request;
}

int main(int argc, const char **argv)
{
    
    
	if(argc != 3)
	{
    
    
		printf("input error: try ‘./client 9899980059901 EMS’\n");
		exit(0);
	}
	cJSON *js=NULL;//JOSN解析结构体
	cJSON *item=NULL;
	cJSON *wer_item=NULL;
	
	int lfd,cfd;	//套接字
	char buf[100*1024],j_buf[1024*100];//接收数组
	
	struct hostent *ht = gethostbyname(INET);//根据域名获得IP
	if(ht == NULL){
    
    
		perror("gethostbyname");
		exit(0);
	}

    sprintf(buf,"%s", inet_ntoa(*((struct in_addr *)(ht->h_addr_list)[0])));
	printf("解析IP:%s\n",buf);
	
	struct sockaddr_in serv_addr;          //服务器地址结构
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    //inet_pton(AF_INET, buf, &serv_addr.sin_addr); //两种方法赋值
	serv_addr.sin_addr = *((struct in_addr *)(ht->h_addr_list[0]));
	
	lfd = socket(AF_INET, SOCK_STREAM, 0);//新建网络套接字
    if (lfd == -1)
        sys_err("socket error");
	
	printf("尝试连接...\n");//尝试连接网络地址
    int ret = connect(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (ret != 0)
        sys_err("connect err");
	printf("已连接到:%s\n",INET);
	
	char *s = httpRequest(argv[1],argv[2],INET);//获取请求数组
	
	printf("发送请求:%s\n",s);
	write(lfd,s,strlen(s)); //发送请求
	usleep(1000);//等一会让数据发送完
	
	read(lfd,buf,sizeof(buf));//获取数据
	//printf("收到报文:%s\n",buf);

	/***砍去头部,不然解析会出错****/
	int j=0,flag=0;
	for(int i=0; i<strlen(buf)+1; i++)
	{
    
    
		if(buf[i] == '{' || flag == 1){
    
    
			flag = 1;
			j_buf[j] = buf[i];
			j++;
		}
	}//printf("砍头后的数据:%s\n",j_buf);
	
	
	//printf("解析JOSN数据..\n");
	js = cJSON_Parse(j_buf); //把去头的报文JOSN进行解析
	//printf("%s\n",cJSON_Print(js));//打印解析好的报文数据
	

	/*获取指定数据 层层查找法,要查看JOSN结构名称*/
	printf("快递物流信息:\n\n");
	item = cJSON_GetObjectItem(js, "result");
	item = cJSON_GetObjectItem(item, "list");

	bzero(buf,sizeof(buf));
	sprintf(buf,"%s",cJSON_Print(item));
	
	for(j=0; j<strlen(buf); j++){
    
    //除去字符串中不好看的字符
		if(buf[j]=='{' || buf[j]=='}' || buf[j]=='"'
		|| buf[j]==',' || buf[j]=='[' || buf[j]==']')
		buf[j] = ' ';
	}
	printf("%s\n",buf);


    //将json结构占用的数据空间释放
    cJSON_Delete(js);
	//关闭连接
	close(lfd);

	return 0;
}


编译运行:在这里插入图片描述

需要代码资料点击这里下载

猜你喜欢

转载自blog.csdn.net/mbs520/article/details/108536218