Linux网络编程之"获取网络天气信息"
需求分析:
    1.需要Linux c 网络编程基础,
    2.需要了解 http 协议
    3.需要天气信息相关api(可以从阿里云上购买,很便宜的!)
    4.需要cJSON解析库(因为获取到的天气信息一般是用cJSON
      封装,有的是用xml封装则需要相关解析库)
cJSON下载链接:https://github.com/DaveGamble/cJSON
cJSON在线代码格式化:http://tool.oschina.net/codeformat/json
cJSON简解及使用:
cJSON核心结构体:
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;           /*键类型*/
    char *valuestring;  /*字符串值*/
    int valueint;       /*整形值*/
    double valuedouble; /*浮点值*/
    char *string;       /*键名称*/
} cJSON;
说明:cJSON数据是以(键-值)形式存在。每个键对应的值都可以
     访问(valuestring、valueint、valuedouble)成员得到。
主要用到的函数:
    1. CSJON_PUBLIC(cJSON*) cJSON_Parse(const char *value);
        用了获得根节点,
    2. CSJON_PUBLIC(cJSON*) cJSON_GetObjectItem(const cJSON* const object, const char *const string);
        用来获得根节点下的子节点,
    3. CSJON_PUBLIC(void) cJSON_Delete(const cJSON *item);
        用来释放为根节点分配的内存!
获取天气的http协议:
    "GET /phone-post-code-weeather?"
    "phone_code=021 "
    "HTTP/1.1\r\n"
    "Host:ali-weather.showapi.com\r\n"
    "Authorization:APPCODE xxxxxx\r\n\r\n"
解释说明:
    "/phone-post-code-weeather"此部分对应于 path格式
    "Host:ali-weather.showapi.com"此部分对应于 接口域名
    "phone_code" 表示城市编号021为上海(记住后面要空格)
    "xxxxxx" 为你购买的APPCODE 这我就不填。。。

相关代码:
#include <netdb.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "common.h"
#include "cJSON.h"
#define SERV_PORT   80
typedef struct sockaddr SA;
void http_request(char *buf, int size, char *city_name);
void analyze_CJSON(const char *json);
char *recv_msg(int sockfd);
int main(int argc, char **argv)
{
    int sockfd;
    struct hostent *hptr = NULL;
    struct sockaddr_in servaddr;
    struct in_addr  **pptr;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        err_quit("socket error");
    }
    char *alias_name = "ali-weather.showapi.com";
    //char *alias_name = "jisutianqi.market.alicloudapi.com";
    //得到接口域名的IP地址
    if ((hptr = gethostbyname(alias_name)) == NULL) {
        err_quit("gethostbyname error for host: %s: %s",
                    alias_name, hstrerror(h_errno));
    }
    pptr = (struct in_addr **)hptr->h_addr_list;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family  =   AF_INET;
    servaddr.sin_port    =   htons(SERV_PORT);
    memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {
        err_quit("connect error");
    }
    char buf[MAXLINE];
     //设置想要查询的城市编号,也可以安其他方式查询
    char *phone_code = "021";
    http_request(buf, MAXLINE, phone_code);
    //发送http请求
    if (write(sockfd, buf, strlen(buf)) != strlen(buf)) {
        err_quit("write error");
    }
    //接收返回信息
    char *json = recv_msg(sockfd);
    //解析CJSON数据
    analyze_CJSON(json);
    return EXIT_SUCCESS;
}
void http_request(char *buf, int size, char *phone_code)
{
    bzero(buf, size);
    snprintf(buf, size, "GET /phone-post-code-weeather?"
                        "phone_code=%s "
                        "HTTP/1.1\r\n"
                        //"Host:jisutianqi.market.alicloudapi.com\r\n"
                        "Host:ali-weather.showapi.com\r\n"
                        "Authorization:APPCODE d487d937315848af80710a06f4592fee\r\n\r\n"
                        , phone_code);
}
/**
 *注意:返回的信息包含http报头信息和实际的CJSON数据,我们只
 *需要CJSON数据,所有需要做一定处理。
 **/
char * recv_msg(int sockfd)
{
    int nread;
    char recvbuf[4096];
    char *begin = NULL, *end = NULL;
    char *lenght = NULL;
    char *data = NULL;
    char tar[] = "Content-Length: ";
    bool flage = true;
    while (1) {
        bzero(recvbuf, sizeof(recvbuf));
        if ((nread = read(sockfd, recvbuf, sizeof(recvbuf))) == 0) {
            break;
        }
        //获得cJSON数据的字节数,存储到lenght中,并调用atoi函数将其转化为int类型
        if (strstr(recvbuf, "403") != NULL || strstr(recvbuf, "Quota Exhausted")) {
            err_quit("your appcode is expire..");
        }
        if (flage) {
            if ((begin = strstr(recvbuf, tar)) != NULL) {
                if ((end = strstr(begin, "\r\n")) != NULL) {
                    lenght = malloc(end - (begin+strlen(tar)));
                    memcpy(lenght, begin+strlen(tar), end-(begin+strlen(tar)));
                    data = calloc(1, atoi(lenght));
                    if (data == NULL) {
                        err_quit("malloc error");
                    }
                    strcpy(data, strrchr(recvbuf, '\n')+1);
                }
            } else {
                continue;
            }
        }
        if (!flage) {
            strcat(data, recvbuf);
        }
        if (strlen(data) == atoi(lenght)) {
            break;
        }
        flage = false;
    }
        printf("atoi(lenght) = %d\n", atoi(lenght));
        free(lenght);
        return data;
}
void analyze_CJSON(const char *json)
{
    //获得根节点
    cJSON *root = cJSON_Parse(json);
    if (root == NULL) {
        err_quit("cJSON_Parse error");
    }
    cJSON *body = cJSON_GetObjectItem(root, "showapi_res_body");
    if (body == NULL) {
        err_quit("body error");
    }
    //判断是否成功得到数据
    if (cJSON_GetObjectItem(body, "ret_code")->valueint == -1) {
        err_quit("json data invalid..");
    }
    cJSON *now = cJSON_GetObjectItem(body, "now");
    if (now == NULL) {
        err_quit("get now failure");
    }
    cJSON *aqiDetai = cJSON_GetObjectItem(now, "aqiDetail");
    if (aqiDetai == NULL) {
        err_quit("get aqiDetai failure");
    }
    cJSON *cityinfo = cJSON_GetObjectItem(body, "cityInfo");
    if (cityinfo == NULL) {
        err_quit("get cityinfo failure");
    }
    cJSON *f1 = cJSON_GetObjectItem(body, "f1");
    if (f1 == NULL) {
        err_quit("get f1 failure");
    }
    cJSON *f2 = cJSON_GetObjectItem(body, "f2");
    if (f1 == NULL) {
        err_quit("get f2 failure");
    }
    cJSON *f3 = cJSON_GetObjectItem(body, "f3");
    if (f1 == NULL) {
        err_quit("get f3 failure");
    }
    printf("            country:\t%s\n", cJSON_GetObjectItem(cityinfo, "c9")->valuestring);
    printf("               area:\t%s\n", cJSON_GetObjectItem(aqiDetai, "area")->valuestring);
    printf("            quality:\t%s\n", cJSON_GetObjectItem(aqiDetai, "quality")->valuestring);
    printf("              pm2_5:\t%s\n", cJSON_GetObjectItem(aqiDetai, "pm2_5")->valuestring);
    printf("               pm10:\t%s\n", cJSON_GetObjectItem(aqiDetai, "pm10")->valuestring);
    printf("                aqi:\t%s\n", cJSON_GetObjectItem(aqiDetai, "aqi")->valuestring);
    printf("\ntoday weather:\n");
    printf("        day_weather:\t%s\n", cJSON_GetObjectItem(f1, "day_weather")->valuestring);
    printf("     day_wind_power:\t%s\n", cJSON_GetObjectItem(f1, "day_wind_power")->valuestring);
    printf(" day_wind_direction:\t%s\n", cJSON_GetObjectItem(f1, "day_wind_direction")->valuestring);
    printf("day_air_temperature:\t%s\n", cJSON_GetObjectItem(f1, "day_air_temperature")->valuestring);
    printf("\ntomorrow weather:\n");
    printf("        day_weather:\t%s\n", cJSON_GetObjectItem(f2, "day_weather")->valuestring);
    printf("     day_wind_power:\t%s\n", cJSON_GetObjectItem(f2, "day_wind_power")->valuestring);
    printf(" day_wind_direction:\t%s\n", cJSON_GetObjectItem(f2, "day_wind_direction")->valuestring);
    printf("day_air_temperature:\t%s\n", cJSON_GetObjectItem(f2, "day_air_temperature")->valuestring);
    printf("\nthe day after tomorrow weather:\n");
    printf("        day_weather:\t%s\n", cJSON_GetObjectItem(f3, "day_weather")->valuestring);
    printf("     day_wind_power:\t%s\n", cJSON_GetObjectItem(f3, "day_wind_power")->valuestring);
    printf(" day_wind_direction:\t%s\n", cJSON_GetObjectItem(f3, "day_wind_direction")->valuestring);
    printf("day_air_temperature:\t%s\n", cJSON_GetObjectItem(f3, "day_air_temperature")->valuestring);
cJSON_Delete(root);
}
												
											Linux网络编程之"获取网络天气信息"的更多相关文章
- 循序渐进Socket网络编程(多客户端、信息共享、文件传输)
		
循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...
 - 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
		
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
 - c/c++ 网络编程 UDP 主机网络信息取得
		
网络编程 UDP 主机网络信息取得 1,if_nametoindex 通过网卡名字取得网卡编号 2,if_indextoname 通过网卡编号取得网卡名字 #include <stdio.h&g ...
 - C# 通过豆瓣网络编程API获取图书信息
		
这篇文章主要是关于如何通过豆瓣API获取信息的书籍,起初,我看到了原来的想法的内容是"C# 网络编程之网页简单下载实现"中通过HttpWebResponse类下载源代码,再通过正則 ...
 - 循序渐进Java Socket网络编程(多客户端、信息共享、文件传输)
		
目录[-] 一.TCP/IP协议 二.TCP与UDP 三.Socket是什么 四.Java中的Socket 五.基本的Client/Server程序 六.多客户端连接服务器 七.信息共享 八.文件传输 ...
 - 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
		
基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...
 - Linux系统编程:socket网络编程(操作篇)
		
一.问题思考 问1.网络通信应用在什么场合?通信的前提是什么? 答1.主要应用在不同主机进程间的互相通信,同一主机的进程也可以使用网络进行通信.通信的前提是如何标识通信进程的唯一,由于不同主机的进程极 ...
 - Python3 与 C# 网络编程之~ 网络基础篇
		
最新版本查看:https://www.cnblogs.com/dotnetcrazy/p/9919202.html 入门篇 官方文档:https://docs.python.org/3/library ...
 - 【网络编程4】网络编程基础-ARP响应(ARP欺骗之中间人攻击)
		
arp欺骗->arp响应 ARP 缓存中毒(ARP欺骗) arp传送原理在于主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址:收到返回消 ...
 
随机推荐
- Java安装及配置开发环境
			
这篇文章里将记录安装Java及配置Java环境的一些步骤,以及基于Java的可扩展开发平台Eclipse的Android开发环境的配置. 准备工具 1.JDK下载 下载地址 关于左侧列栏的Java S ...
 - 微信授权登录(OAuth2.0)--  随记
			
1.OAuth2.0简介 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户 ...
 - 华东交通大学2017年ACM“双基”程序设计竞赛 1001
			
Problem Description 最近流行吃鸡,那就直接输出一行"Winner winner ,chicken dinner!"(没有双引号)模板代码:#include &l ...
 - 【Java密码学】Java SE 6中XML数字签名的实现
			
package test.xml.signature; import java.io.File; import java.io.FileInputStream; import java.io.File ...
 - 小试OKR一季度之后有感分享,你要不要试试ORK?
			
封面 OKR已经在国内热火朝天有一阵子了,为了适当的赶时髦,从年初开始团队内部小范围使用ORK模式以便测试团队会有什么化学反应.这篇文章打算写写心得感受,供大家围观产考. 老一套先摆一下概念 OKR( ...
 - Properties IO持久化
			
Properties IO持久化 Properties类表示一组持久的属性. Properties可以保存到流中或从流中加载. 属性列表中的每个键及其对应的值都是一个字符串. 方法: String g ...
 - prototype 以及 constructor 属性的理解
			
1 为什么 xx.constructor.prototype 可以访问到当前对象的原型. 'str'.constructor.prototype 'str'.constructor 指向当前 ...
 - kickstart2019 round_A B. Parcels
			
思路: 利用了曼哈顿距离和切比雪夫距离之间的转化. 参考: https://blog.csdn.net/Dylan_Frank/article/details/88985444 https://www ...
 - vim常用命令大全
			
在命令状态下对当前行用== (连按=两次), 或对多行用n==(n是自然数)表示自动缩进从当前行起的下面n行.你可以试试把代码缩进任意打乱再用n==排版,相当于一般IDE里的code format.使 ...
 - spring-framework-3.0.2RELEASE之后为啥没有依赖包了?
			
缘起:莫莫接到新任务要学习spring mvc,于是在网上找了个demo文档跟着一起做.这个是学习的网址: http://www.open-open.com/doc/view/a6462d9a2e2b ...