我正在尝试用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流。
编辑:
感谢您的回复。我原来的计划有效。对此进行了调试,发现企业防火墙阻止了数据包,因此我从未得到过响应。
对于@eyllanesc发布的答案 - 此代码部分有效。由于某些未知原因,来自服务器的FIN数据包不会立即出现。自发送第一个数据包以来总是需要4分钟。 因此程序在终止之前会持续4分钟。谢谢你的努力。
答案 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"
}