Пытаюсь скачать картинку (вот эту: http://ru.fishki.net/picsw/112010/23/joke.jpg) Делаю я это так: Code: #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> #include <winsock2.h> #pragma comment( lib, "wsock32.lib" ) sockaddr_in server_info; int get_jpg(char http_site[64]) { int sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (connect(sock, (struct sockaddr*)&server_info, sizeof(server_info)) == 0) { char send_packet[4024], recv_packet[4097], temp[4024]; sprintf(temp, "GET %s HTTP/1.0\r\nUser-Agent: Opera/10.60 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.60\r\nHost: ru.fishki.net\r\nConnection: Close\r\n\r\n", http_site); strcpy(send_packet, temp); send(sock, send_packet, strlen(send_packet), 0); int i3 = 0, last_res, int_temp; while (1) { int_temp = recv(sock, recv_packet, 4096, 0); if ((int_temp == 0) || (int_temp == -1)) break; i3 += int_temp; ZeroMemory(recv_packet, 4096); } } closesocket(sock); return 0; } int main() { WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); server_info.sin_addr.s_addr = inet_addr("82.98.86.161"); server_info.sin_port = htons(80); server_info.sin_family = AF_INET; get_jpg("http://ru.fishki.net/picsw/112010/23/joke.jpg");//recv возврашает -1 //get_jpg("http://ru.fishki.net/picsw/index.php");//recv не возвращает 0 } Но recv возвращает -1! Хотя если попробывать запросить страницу http://ru.fishki.net/picsw/index.php - recv все нормально возвращает. Каков должен быть запрос чтобы все нормально принималось? (пробывал даже браузерный запрос -> все так же recv == -1)
попробуй замени get_jpg("http://ru.fishki.net/picsw/112010/23/joke.jpg") на get_jpg("/picsw/112010/23/joke.jpg")
1) rudi прав. Тыже юзаешь не прокси а сразу запрос на сервак. 2) strcpy(send_packet, temp); Нафига?? а сразу ты не можешь что-ли отправить temp 3) если бы заюзал вместо sprintf апишку wsprintfA то онабы заодно тебе и вернула размер результирующей строки не надо былобы потом вычислять длину перед отправкой 4) while (1) - нафига? если for (; более оптимальна 5) if ((int_temp == 0) || (int_temp == -1)) break; - нафига? не проще ли if (int_temp <= 0) break; 6) fwrite(recv_packet, strlen(recv_packet), 1, h_file); хоть ты и закоментил но всё равно это не правильно. потому что картинка двоичная и по этом strlen не прокатит. да и не нужно это тебе потому что int_temp уже имет размер считанных данных 7) сокет забываешь проверять при создании 8) забываешь отрезать HTTP заголовок. Насчет проблемы твой. Нафига так сильно привязываться к IP и к имени сайта? Проще уже получать IP на основании доменного имени
Вот кусок из одной моей софтины Code: unsigned int Host2Ip(char * host) { struct hostent * p; unsigned int ret; ret = inet_addr(host); if (ret == INADDR_NONE) // if host is not ip { p = gethostbyname(host); // get ip if (p) // if ok { // save ip ret = *(unsigned int*)(p->h_addr); } else // if error { ret = INADDR_NONE; } } // return IP or INADDR_NONE return ret; } // формат линка site.com/dir/file.ext?param=val DWORD Download(char* from_link) { DWORD ret = 0; SOCKET sock; char * host; char link[256]; char header[4096]; DWORD ip; int len; SOCKADDR_IN sa; lstrcpyA(link, from_link); host = link; while (*link != 0x00) { if (*link == '/') { *link = 0x00; link++; break; } link++; } len = wsprintfA(header, "GET /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\n\r\n", link, host); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock != INVALID_SOCKET) { ip = Host2Ip(host); if (ip != INADDR_NONE) { sa.sin_addr.S_un.S_addr = ip; sa.sin_family = AF_INET; sa.sin_port = htons(80); if (!connect(sock, (SOCKADDR*)&sa, sizeof(sa))) { send(sock, header, len, 0); for (;;) { len = recv(sock, header, 4096, 0); if (len <= 0) { break; } тут обработка данных ret = 1; } } } closesocket(sock); } return ret; }
Помнится как то такой запрос (без строки http...) не прошел (возвращал не 200) Спасибо буду знать. Всегда задавался вопросом - почему? Ну да, не подумал. Меня всегда интересовал вопрос - когда сокет может вернуть -1 ? (если же перед этим я к примеру проверил WSAStartup) Т.е.? Это по типу твоей функции Host2Ip?
Рабочий вариант PHP: #include "stdafx.h" #include <iostream> #include <windows.h> #include <winsock2.h> #define MAXINBUFFLEN 1024 *100 int get_jpg(char *http_site); #pragma comment( lib, "wsock32.lib" ) int main() { WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); get_jpg("/picsw/112010/23/joke.jpg"); return 0; } //-------------------------------------------------------------- int get_jpg(char *http_site) { struct hostent *hp; struct sockaddr_in serv; char inbuf[MAXINBUFFLEN], send_packet[4024]; SOCKET sock; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); hp = gethostbyname("ru.fishki.net"); serv.sin_family = AF_INET; serv.sin_port = htons(80); memcpy ((char *)&serv.sin_addr,hp->h_addr,hp->h_length); int con_s = connect(sock, (struct sockaddr *) &serv,sizeof(serv)); if (con_s != -1) { sprintf(send_packet, "GET %s HTTP/1.0\r\n" "User-Agent: Opera/10.60 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.60\r\n" "Host: ru.fishki.net\r\n" "Connection: Close\r\n\r\n", http_site); send(sock, send_packet, strlen(send_packet), 0); int bits =0, allbits = 0; while(true) { bits = recv(sock,(inbuf+allbits),20000,0); if(bits <= 0){inbuf[allbits] = '\0'; break;}; allbits += bits; if(allbits > (MAXINBUFFLEN - 20000)) {inbuf[allbits] = '\0'; break;} } closesocket(sock); if(strstr(inbuf,"Content-Type: image/jpeg")) { char *wp = inbuf; int totalk = 0, pos = 1, length = 0; while(pos != 0) { pos = strcspn(wp,"\r\n"); totalk = totalk + pos + 2; wp = wp + 2 + pos; } length = allbits - totalk; FILE *fp; fp = fopen("Image.jpg","wb"); for(int m = 0; m < length; m++) { char s = *wp; fputc(s,fp); wp++; }; fclose(fp); } } return 0; }
для while (1) без оптимизации да и многи компиляторами генерится код проверки условия 1=1 mov eax, 1 test eax, eax je метка А для for(; это не генирится потому что там нет условия для цикла и это считай равноценно m1: **** if (***) goto m2 ** goto m1; m2: Насчет сокетов - редкий но вызывает случай, в частности всякий там софт сторонний который может чтото там хукать итд итп. Или когда привышен лими открытых сокетов. Для XP SP2 когдато ловил его ан 170к
2 rudi 1) hp = gethostbyname("ru.fishki.net"); а если глюк днс или еще чегонить и домен не будет найден и вернется NULL то на строчке memcpy ((char *)&serv.sin_addr,hp->h_addr,hp->h_length); будет глюк 2) на счет считывания ты извратился +/-20000 это жесть. самый лучший вариант (покрайней мере для меня). Ты никогда не считаешь больше чем буфер потому что recv само прервется когда запрощенное число байт станет <= 0 Code: for (;;) { len = recv(sock, buf + full_len, max - full_len, 0); if (len > 0) { full_len += len; **** } else { *** } }
Никак не пойму в чем была проблема. Почему именно gethostbyname спасает в этой ситуации? Пробывал под дебагом посмотреть структуру serv.sin_addr. И я увидел что IP'ы совершенно разные (к примеру если сравнивать результат команды ping ru.fishki.net (cmd) & gethostbyname, но почему они разные?).
Я ничего не путаю. После строки (см. что прислал rudi): memcpy((char *)&server_info.sin_addr,hp->h_addr,hp->h_length); я смотрю что находится в server_info.sin_addr.S_un_b, и вижу что последняя цифра совершенно другая. Пример: ping ru.fishki.net говорит нам: 194.186.88.12 а server_info.sin_addr.S_un_b это (после gethostbyname естественно): 194.186.88.3
А, понятно. Ну так выполни пару раз в cmd команду ping ru.fishki.net. IP сервера будет иногда менятся (а именно как раз последняя цифра).
А потому что для A записи в DNS можно прописать несколько IP для домена. А если еще и TTL маленький поставить, то еще класс будет. т.е. такая вот хитрая система распределения трафа. Домен один, а там может быть десятки серваков который обрабатывают запросы.