C中的REST客户端

时间:2016-11-17 03:24:22

标签: c rest sockets

我正在尝试用C编写REST客户端。目前它是独立的,但稍后,我打算将其移植到我们的代码库。

我正在使用gcc在centos 6.5上测试它。

我开始使用https://gist.github.com/nolim1t/126991的代码作为参考。这是由几位成员在quora中提出的。

我调整了上面的代码以满足我的需求。当我尝试这个时,我无法从其余服务器获得有效的响应。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>

int socket_connect(char *host, in_port_t port){
    struct hostent *hp;
    struct sockaddr_in addr;
    int on = 1, sock;
    if((hp = gethostbyname(host)) == NULL){
    herror("gethostbyname");
    exit(1);
}
    bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
    addr.sin_port = htons(port);
    addr.sin_family = AF_INET;
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));

    if(sock == -1){
        perror("setsockopt");
        exit(1);
    }

    if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
        perror("connect");
        exit(1);
    }
    return sock;
}

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]){
    int fd;
    int cx;
    char inputBuffer[BUFFER_SIZE];
    char buffer[BUFFER_SIZE];
    if(argc < 4){
        fprintf(stderr, "Usage: %s <hostname> <port> <other-args>\n", argv[0]);
        exit(1);
    }
    fd = socket_connect(argv[1], atoi(argv[2]));
    if(fd)
    {
        printf("socket success\n");
    }

    cx = snprintf(inputBuffer, BUFFER_SIZE, "GET %s\r\n", argv[3]);
//  snprintf(inputBuffer, argv[3], strlen(argv[3]));

    write(fd, inputBuffer, cx); // write(fd, char[]*, len);
    bzero(buffer, BUFFER_SIZE);
    printf("reading response\n");
    while(read(fd, buffer, BUFFER_SIZE - 1) != 0){
        fprintf(stderr, "%s", buffer);
        bzero(buffer, BUFFER_SIZE);
    }
    shutdown(fd, SHUT_RDWR);
    close(fd);
    return 0;
}

这是我正在访问的其他网址: http://maps.googleapis.com/maps/api/geocode/json?address=chicago

当我通过浏览器访问它时,我能够访问json数据/响应。 但是,当我使用C程序时,我得到以下输出。

#./rest maps.googleapis.com 80 /maps/api/geocode/json?address=chicago
socket success
reading response

它无限期地停留在那里。

当我通过C程序以及浏览器访问时,我正在附加数据包捕获和tcp流。

Packet Capture when I use the C program

TCP stream for the C program request

packet capture for browser request

编辑:

感谢您的回复。我原来的计划有效。对此进行了调试,发现企业防火墙阻止了数据包,因此我从未得到过响应。

对于@eyllanesc发布的答案 - 此代码部分有效。由于某些未知原因,来自服务器的FIN数据包不会立即出现。自发送第一个数据包以来总是需要4分钟。 因此程序在终止之前会持续4分钟。谢谢你的努力。

1 个答案:

答案 0 :(得分:1)

我的解决方案基于以下link

我的解决方案是:

#include <stdio.h> /* printf, sprintf */
#include <string.h>
#include <stdlib.h> /* exit */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{
    /* first what are we going to send and where are we going to send it? */

    if(argc < 4){
        fprintf(stderr, "Usage: %s <hostname> <port> <resource>\n", argv[0]);
        exit(1);
    }

    char *host =         argv[1];
    int portno = atoi(argv[2]);

    char message_fmt[1024];

    strcpy (message_fmt,"GET ");
    strcat(message_fmt, argv[3]);
    strcat(message_fmt," HTTP/1.0\r\n\r\n");

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total;
    char message[1024],response[4096];

    /* fill in the parameters */
    sprintf(message,message_fmt,argv[1],argv[2]);
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

    /* send the request */
    total = strlen(message);
    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);

    /* receive the response */
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response+received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while (received < total);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("Response:\n%s\n",response);

    return 0;
}

输入:

./rest maps.googleapis.com 80 /maps/api/geocode/json?address=chicago

输出:

Request:
GET /maps/api/geocode/json?address=chicago HTTP/1.0


Response:
HTTP/1.0 200 OK
Content-Type: application/json; charset=UTF-8
Date: Thu, 17 Nov 2016 04:01:52 GMT
Expires: Fri, 18 Nov 2016 04:01:52 GMT
Cache-Control: public, max-age=86400
Access-Control-Allow-Origin: *
Server: mafe
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Accept-Ranges: none
Vary: Accept-Language,Accept-Encoding

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "Chicago",
               "short_name" : "Chicago",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Cook County",
               "short_name" : "Cook County",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Illinois",
               "short_name" : "IL",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Chicago, IL, USA",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 42.023131,
                  "lng" : -87.52366099999999
               },
               "southwest" : {
                  "lat" : 41.6443349,
                  "lng" : -87.9402669
               }
            },
            "location" : {
               "lat" : 41.8781136,
               "lng" : -87.6297982
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 42.023131,
                  "lng" : -87.52404399999999
               },
               "southwest" : {
                  "lat" : 41.6443349,
                  "lng" : -87.9402669
               }
            }
         },
         "place_id" : "ChIJ7cv00DwsDogRAMDACa2m4K8",
         "types" : [ "locality", "political" ]
      }
   ],
   "status" : "OK"
}