2016-11-17 163 views
0

我想在C中编写一个REST客户端。目前它是独立的,但后来我打算把它移植到我们的代码库中。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

不可重复,'./ your_prog maps.googleapis .com 80“/ maps/api/geocode/json?address = chicago”'吐出正确的结果 – deamentiaemundi

+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" 
} 
+0

感谢您的努力。这仍然不能完全工作。请参阅问题的编辑部分。 –