2016-11-17 250 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

感謝您的努力。這仍然不能完全工作。請參閱問題的編輯部分。 –