v1A*_*xvw 7 html c download hang recv
最近我开始学习本指南,开始从互联网上下载文件.我读了它并想出了下面的代码来下载一个网站的HTTP主体.唯一的问题是,它不起作用.调用recv()调用时代码停止.它不会崩溃,它只是继续运行.这是我的错吗?我使用错误的approch吗?我打算使用代码不仅下载.html文件的内容,还要下载其他文件(zip,png,jpg,dmg ...).我希望有人可以帮助我.这是我的代码:
#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, 0, 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, const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(status);
}
Run Code Online (Sandbox Code Playgroud)
D.S*_*ley 12
如果你想使用HTTP来获取文件,那么libcURL可能是你在C中最好的选择.但是,如果你使用它作为一种学习网络编程的方法,那么你将不得不学习更多关于HTTP的知识.检索文件.
您在当前程序中看到的是,您需要先发送对文件的显式请求,然后才能检索它.我将从阅读RFC2616开始.不要试图理解这一切 - 这个例子需要阅读很多.阅读第一部分以了解HTTP的工作原理,然后阅读第4,5和6节以了解基本的消息格式.
以下是stackoverflow Questions页面的HTTP请求的示例:
GET http://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
Run Code Online (Sandbox Code Playgroud)
我认为这是一个最小的要求.我明确地添加了CRLF,以显示如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
Run Code Online (Sandbox Code Playgroud)
如果您想使用HTTP获取文件,这个简单的示例应该可以让您了解要实现的内容.这是最好的情况,最简单的例子.这不是我会轻易承担的事情,但它可能是学习和欣赏HTTP的最佳方式.
如果您正在寻找一种学习网络编程的简单方法,这是一个很好的开始.我建议拿一份TCP/IP Illustrated,第1卷和UNIX网络编程,第1卷.这些可能是真正学习如何编写基于网络的应用程序的最佳方式.我可能会从编写FTP客户端开始,因为FTP是一个更简单的协议.
如果您尝试了解与HTTP相关的详细信息,那么:
telnet server 80并手动输入请求的示例--verbose和--include命令行选项,以便您可以看到发生了什么只是不打算为企业使用编写自己的HTTP客户端.你不想这样做,相信我是一个一直在维持这样一个错误的人...