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


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

查看所有标签

猜你喜欢:

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

Essential C++中文版

Essential C++中文版

[美] Stanley B. Lippman / 侯捷 / 华中科技大学出版社 / 2001-8 / 39.80元

书中以4个面向来表现C++的本质:procedural(程序性的)、generic(泛型的)、object-based(个别对象的)、object-oriented(面向对象的),全书围绕着一系列逐渐繁复的程序问题,以及用以解决这些问题的语言特性。循此方式,读者不只学到C++的函数和结构,也会学习到它们的设计目的和基本原理。一起来看看 《Essential C++中文版》 这本书的介绍吧!

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

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具