C语言实现GET请求调用API

栏目: C · 发布时间: 7年前

内容简介:C语言实现GET请求调用API

使用 python 可以很容易地实现简单的 HTTP 请求,因为系统库封装了构建 HTTP 请求报文的底层操作,面向用户的是简单地函数调用,而通过 C语言 实现 HTTP 请求必须了解 HTTP 协议的原理,这里推荐经典的 《HTTP权威指南》 和入门的 《图解HTTP》

HTTP协议简介

HTTP报文分为请求报文和响应报文,报文分为三个部分:起始行,首部块和正文主题,这里着重谈谈请求报文的构建

另外,使用浏览器的调试工具->网络选项也能直观地分析每个HTTP请求的特征

C语言实现GET请求调用API

C实现HTTP请求的细节

C语言实现GET请求调用API

请求报文

请求报文的格式如下:

<method> <requests-URL> <version>
<headers>

<entire body>

method 代表对服务器资源获取的动作,常见的有 getpost

requests-URL 代表请求的统一资源定位符,也就是完整的网页链接。

versionHTTP 版本,目前已 HTTP1.1 最为常见。

headers 表示请求报文的首部,常见的防盗链 refer ,浏览器信息 user-agent 等等都在这里定义,注意这里的每一项属性参数以每行末尾的 \n\r 来分隔。

响应报文

和请求报文类似,只介绍其独特的地方

<version> <status> <reason-phrase>
<headers>

<entire body>

statusreason-phrase 表示状态码和原因短语,比较常见的就是 200 OK404 Not Found502 Bad Gateway

entire body 报文的实体部分,一般来说就是发往浏览器的整个 HTML 文件,当然还有图片,二进制文件等等其他一些资源。

GET请求

创建socket

//定义的缓冲区用来存放socket发送和接受的数据 也就是HTTP请求和响应报文
char buff[2048];
int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
if ( sockfd < 0 )
{
    printf( "create socket error!\n" );
    exit( -1 );
}

struct sockaddr_in serveraddr;
memset( &serveraddr, 0, sizeof(serveraddr) );
serveraddr.sin_family    = AF_INET;
// HTTP服务 TCP 80端口
serveraddr.sin_port    = htons( 80 );
// apis.map.qq.com 解析地址
inet_pton( AF_INET, "182.254.11.29", &serveraddr.sin_addr.s_addr );

if ( connect( sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr) ) < 0 )
{
    printf( "connect error!\n" );
    exit( -2 );
}

memset( buff, 0, sizeof(buff) );

测试用例还是上回 腾讯地图API ,注册过后拿到开发密钥XXXXX-XXXXX-XXXXX-XXXXX-XXXXX

注意下应用类型选择 浏览器 ,名字什么的可以随便填

C语言实现GET请求调用API

根据API说明构建HTTP请求报文

snprintf( buff, sizeof(buff) - 1,
     "GET /ws/geocoder/v1/?location=%s,%s&key=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX&get_poi=1&coord_type=3 HTTP/1.1\r\n"
     "Host: apis.map.qq.com\r\n"
     "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n"
     "\r\n",
     argv[1], argv[2]
     );

发送请求

if ( write( sockfd, buff, strlen( buff ) ) != strlen( buff ) )
{
    return(-1); /* 发送出错返回-1 */
}
memset( buff, 0, sizeof(buff) );
size_t size;
if ( (size = read( sockfd, buff, sizeof(buff) ) ) < 0 ) /* 从服务器端读取 */
{
    return(-1);
}
printf( "HTTP响应报文:\n%s\n", buff );
close( sockfd );
}

响应实例

HTTP响应报文:
HTTP/1.1 200 OK
X-LIMIT: current_qps=1; limit_qps=5; current_pv=21; limit_pv=10000
Content-Type: application/json; charset=utf-8
Content-Length: 9528
Date: Mon, 29 May 2017 00:27:04 GMT
Connection: keep-alive

{
    "status": 0,
    "message": "query ok",
    "request_id": "6274752708360945856",
    "result": {
        "location": {
            "lat": 30.542301,
            "lng": 114.392483
        },
        "address": "湖北省武汉市武昌区东湖东路",
        "formatted_addresses": {
            "recommend": "武昌区东湖生态旅游风景区东湖",
            "rough": "武昌区东湖生态旅游风景区东湖"
...

响应报文长度可能会超过 buff 的长度,所以会显示不全

数据处理

拿到响应报文后,还需要把有用的地理信息从字符数组中提取出来,这里我只提取 recommendrough 的值,如果需要解析整个 JSON 需要用到 cJson 库。

匹配处理

字符数组匹配子串用的是 strstr() 函数

int repResolve( char *rep, char *recmd, char* rough )
{
  //p q接受匹配后的起始地址
    char    * p    = strstr( rep, "recommend" );
    char    * q    = strstr( rep, "rough" );
    if ( p )
    {
    // recommend": " r到"一共13个字符
        p = p + 13;
    // 地名" 一直匹配到引号的结束 
        while (!((*p) == '\"'))
        {
      //字符串复制
            *recmd++ = *p++;
        }
    //字符串末尾补0
        *recmd = '\0';
    }
    if ( q )
    {
        q += 9;
        while (!((*q) == '\"'))
        {
            *rough++ = *q++;
        }
        *rough = '\0';
    }
    return(0);
}

完整代码

#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          
#include <sys/socket.h>

//填写你自己申请的APIkey
const char* apikey="";

int repResolve( char *rep, char *recmd, char* rough )
{
  //p q接受匹配后的起始地址
    char    * p    = strstr( rep, "recommend" );
    char    * q    = strstr( rep, "rough" );
    if ( p )
    {
    // recommend": " r到"一共13个字符
        p = p + 13;
    // 地名" 一直匹配到引号的结束 
        while (!((*p) == '\"'))
        {
      //字符串复制
            *recmd++ = *p++;
        }
    //字符串末尾补0
        *recmd = '\0';
    }
    if ( q )
    {
        q += 9;
        while (!((*q) == '\"'))
        {
            *rough++ = *q++;
        }
        *rough = '\0';
    }
    return(0);
}

int main( int argc, char **argv )
{
    char    buff[2048]    = { '\0' };
    char    recmd[512]    = { '\0' };
    char    rough[512]    = { '\0' };
    int    sockfd        = socket( AF_INET, SOCK_STREAM, 0 );
    if ( sockfd < 0 )
    {
        printf( "create socket error!\n" );
        exit( -1 );
    }

    struct sockaddr_in serveraddr;
    memset( &serveraddr, 0, sizeof(serveraddr) );
    serveraddr.sin_family    = AF_INET;
    serveraddr.sin_port    = htons( 80 );

    inet_pton( AF_INET, "182.254.11.29", &serveraddr.sin_addr.s_addr );
    /* inet_pton(AF_INET, "apis.map.qq.com", &serveraddr.sin_addr.s_addr); */

    if ( connect( sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr) ) < 0 )
    {
        printf( "connect error!\n" );
        exit( -2 );
    }

    memset( buff, 0, sizeof(buff) );
    snprintf( buff, sizeof(buff) - 1,
          "GET /ws/geocoder/v1/?location=%s,%s&key=%s&get_poi=1&coord_type=3 HTTP/1.1\r\n"
          "Host: apis.map.qq.com\r\n"
          "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n"
          "\r\n",
        argv[1], argv[2] ,apikey
          );

    if ( write( sockfd, buff, strlen( buff ) ) != strlen( buff ) )
    {
        return(-1);
    }
    memset( buff, 0, sizeof(buff) );
    size_t size;
    if ( (size = read( sockfd, buff, sizeof(buff) ) ) < 0 )
    {
        return(-1);
    }

    /*步骤4:关闭socket*/
    printf( "\nTCP响应长度: %d\n", size );
    printf( "HTTP响应报文长度: %d\n", strlen( buff ) );

    //printf( "HTTP响应报文:\n%s\n", buff );
  printf("HTTP响应报文:\n%.*s\n", 290, buff); 
    repResolve( buff, recmd, rough );

    printf( "当前坐标: \n%s %s\n", argv[1], argv[2] );
    printf( "当前位置: \n\t%s\n", recmd );
    printf( "\t%s\n", rough );

    close( sockfd );
}

第一个参数接受纬度,第二个参数接受精度,请求效果如下

C语言实现GET请求调用API


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Data Structures and Algorithm Analysis in Java

Data Structures and Algorithm Analysis in Java

Mark A. Weiss / Pearson / 2011-11-18 / GBP 129.99

Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course wa......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换