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 這我就不填。。。
![這裏寫圖片描述](http://img.blog.csdn.net/20170815164731926?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQ29taW5nRmx5aW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
相關代碼:

#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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章