Недавно я начал брать это руководство для запущения меня при загрузке файлов из Интернета. Я считал его и придумал следующий код для загрузки Тела HTTP веб-сайта. Единственная проблема, она не работает. Код останавливается при назывании recv () вызовом. Это не отказывает, это просто продолжает работать. Этот мой отказ? Я использую несправедливость approch? Я намерение использовать код к не только загружаю содержание .html-файлов, но также и загружать другие файлы (zip, png, jpg, dmg...). Я надеюсь, что существует кто-то, который может помочь мне. Это - мой код:
#include
#include /* SOCKET */
#include /* struct addrinfo */
#include /* exit() */
#include /* memset() */
#include /* errno */
#include /* close() */
#include /* IP Conversion */
#include /* 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);
}
Если вы хотите получать файлы с помощью HTTP, то libcURL, вероятно, будет лучшим вариантом на C. Однако, если вы используете это как способ изучения сетевого программирования, то вам придется узнать немного больше о HTTP, прежде чем вы сможете получить файл.
То, что вы видите в вашей текущей программе, это то, что вам нужно послать явный запрос на файл, прежде чем вы сможете его получить. Я бы начал с чтения RFC2616. Не пытайтесь понять все - для данного примера это очень много. Прочитайте первый раздел, чтобы понять, как работает HTTP, затем прочитайте разделы 4, 5 и 6, чтобы понять основной формат сообщений.
Вот пример того, как выглядит HTTP-запрос для страницы Вопросы stackoverflow:
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
Я считаю, что это минимальный запрос. Я добавил 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
Этот простой пример должен дать вам представление о том, во что вы ввязываетесь, если хотите захватывать файлы с помощью HTTP. Это самый лучший, самый простой пример. Это не то, за что я бы взялся легкомысленно, но это, вероятно, лучший способ изучить и оценить HTTP.
Если вы ищете простой способ изучить сетевое программирование, это достойный способ начать. Я бы рекомендовал приобрести TCP/IP Illustrated, Volume 1 и UNIX Network Programming, Volume 1. Это, вероятно, лучший способ научиться писать сетевые приложения. Я бы, вероятно, начал с написания FTP-клиента, поскольку FTP - гораздо более простой протокол для начала.
Если вы пытаетесь узнать подробности, связанные с HTTP, то:
telnet server 80
и вводя запросы вручную--verbose
и --include
, чтобы вы могли видеть, что происходитТолько не планируйте писать свой собственный HTTP-клиент для корпоративного использования. Вы не захотите этого делать, поверьте мне, как человеку, который поддерживает такую ошибку уже некоторое время...
Вы должны отправить HTTP-запрос, прежде чем ожидать ответа. В настоящее время ваш код просто ждет ответа, который никогда не приходит.
Также не пишите комментарии заглавными буквами.
Проблема в том, что вам необходимо реализовать протокол HTTP. Загрузка файла - это не просто вопрос подключения к серверу, вы должны отправить HTTP-запросы (вместе с правильным HTTP-заголовком), прежде чем получите ответ. После этого вам все равно нужно будет проанализировать возвращенные данные, чтобы удалить дополнительные заголовки HTTP.
Если вы просто пытаетесь загрузить файлы с помощью C, я предлагаю библиотеку cURL , которая выполняет HTTP-работу за вас.