#include <stdio.h> #include <sys/socket.h> /* SOCKET */ #include <netdb.h> /* struct addrinfo */ #include <stdlib.h> /* exit() */ #include <string.h> /* memset() */ #include <errno.h> /* errno */ #include <unistd.h> /* close() */ #include <arpa/inet.h> /* IP Conversion */ #include <stdarg.h> /* va_list */ #define SERVERNAME "developerief2.site11.com" #define PROTOCOL "80" #define MAXDATASIZE 1024*1024 void errorOut(int status,const char *format,...); void *get_in_addr(struct sockaddr *sa); int main (int argc,const char * argv[]) { int status; // GET ADDRESS INFO struct addrinfo *infos; struct addrinfo hints; // fill hints memset(&hints,sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; // get address info status = getaddrinfo(SERVERNAME,PROTOCOL,&hints,&infos); if(status != 0) errorOut(-1,"Couldn't get addres information: %s\n",gai_strerror(status)); // MAKE SOCKET int sockfd; // loop,use first valid struct addrinfo *p; for(p = infos; p != NULL; p = p->ai_next) { // CREATE SOCKET sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol); if(sockfd == -1) continue; // TRY TO CONNECT status = connect(sockfd,p->ai_addr,p->ai_addrlen); if(status == -1) { close(sockfd); continue; } break; } if(p == NULL) { fprintf(stderr,"Failed to connect\n"); return 1; } // LET USER KNOW char printableIP[INET6_ADDRSTRLEN]; inet_ntop(p->ai_family,get_in_addr((struct sockaddr *)p->ai_addr),printableIP,sizeof(printableIP)); printf("Connection to %s\n",printableIP); // GET RID OF INFOS freeaddrinfo(infos); // RECEIVE DATA ssize_t receivedBytes; char buf[MAXDATASIZE]; printf("Start receiving\n"); receivedBytes = recv(sockfd,buf,MAXDATASIZE-1,0); printf("Received %d bytes\n",(int)receivedBytes); if(receivedBytes == -1) errorOut(1,"Error while receiving\n"); // null terminate buf[receivedBytes] = '\0'; // PRINT printf("Received Data:\n\n%s\n",buf); // CLOSE close(sockfd); return 0; } void *get_in_addr(struct sockaddr *sa) { // IP4 if(sa->sa_family == AF_INET) return &(((struct sockaddr_in *) sa)->sin_addr); return &(((struct sockaddr_in6 *) sa)->sin6_addr); } void errorOut(int status,...) { va_list args; va_start(args,format); vfprintf(stderr,format,args); va_end(args); exit(status); }
解决方法
您在当前程序中看到的是,您需要先发送文件的明确请求,然后才能检索它.我将从阅读RFC2616开始.不要试图理解这一切 – 这个例子需要阅读很多.阅读first section以了解HTTP的工作原理,然后阅读第4,5,and 6节以了解基本的消息格式.
以下是stackoverflow Questions页面的HTTP请求的示例:
GET https://stackoverflow.com/questions HTTP/1.1\r\n Host: stackoverflow.com:80\r\n Connection: close\r\n Accept-Encoding: identity,*;q=0\r\n \r\n
我认为这是一个最小的要求.我明确添加了CRLF,以显示空行用于终止请求标头块as described in RFC2616.如果省略Accept-Encoding
标头,则结果文档可能会被转换为gzip压缩流,因为HTTP明确允许这样做,除非你告诉服务器你不想要它.
服务器响应还包含描述响应的元数据的HTTP标头.以下是上一个请求的响应示例:
HTTP/1.1 200 OK\r\n Server: Nginx\r\n Date: Sun,01 Aug 2010 13:54:56 GMT\r\n Content-Type: text/html; charset=utf-8\r\n Connection: close\r\n Cache-Control: private\r\n Content-Length: 49731\r\n \r\n \r\n \r\n <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ... 49,667 bytes follow
如果您想使用HTTP获取文件,这个简单的示例应该让您了解要实现的内容.这是最好的情况,最简单的例子.这不是我会轻易承担的事情,但它可能是学习和欣赏HTTP的最佳方式.
如果您正在寻找一种学习网络编程的简单方法,这是一个很好的开始方式.我建议拿起TCP/IP Illustrated,Volume 1和UNIX Network Programming,Volume 1的副本.这些可能是真正学习如何编写基于网络的应用程序的最佳方法.我可能从编写FTP client开始,因为FTP是一个更简单的协议开始.
如果您尝试了解与HTTP相关的详细信息,那么:
>购买HTTP: the Definitive Guide并阅读
>阅读RFC2616直到您理解为止
>尝试使用telnet服务器80并手动输入请求的示例
>下载cURL客户端并使用–verbose和–include命令行选项,以便您可以看到发生了什么
>阅读Fielding’s dissertation,直到HTTP真的有意义.
只是不打算为企业使用编写自己的HTTP客户端.你不想这样做,相信我是一个一直在维持这样一个错误的人…