Задача: по шурому накатать скачивалку html-странички вместе с картинками. Проблема: чтение первой странички OK, все последующие - обломы. Вот проблемный код без всего лишнего. Code (Text): #include <windows.h> #include <alloc.h> #include <string.h> #include <stdio.h> #define MAXMES 0x200 #define MAXBUF 0xffff char ip[]={"64.142.28.160"}; // Строка IP char get[MAXMES]; // Строка запроса GET char sBuf[MAXBUF]; // Читаемый буфер int iRec, iEnd, i, e; SOCKET SendSocket; WSADATA WSAData; SOCKADDR_IN remoteAddr; void getpage(char *pagename) { // GET + скачка + отображение get[0] = 0; strcat(get, "GET "); strcat(get, pagename); // Урл странички strcat(get, " HTTP/1.1\r\n" ); // При 1.0 не работает keep-alive !!! strcat(get, "Accept: */*\r\n" ); strcat(get, "Accept-Encoding: gzip,deflate\r\n"); strcat(get, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)\r\n"); strcat(get, "Host: www.john.org\r\n"); strcat(get, "Connection: Keep-Alive\r\n"); strcat(get, "\r\n"); e = send( SendSocket, get, strlen(get), 0); if (e==-1) printf("\nsend error %u\n", WSAGetLastError()); memset( sBuf, 0, MAXBUF); iEnd = 0; // Обнуляем while (1) { iRec = recv(SendSocket, (LPSTR) sBuf+iEnd, sizeof(sBuf)-iEnd, 0); if (iRec==-1) printf("\nrecv error %u\n", WSAGetLastError()); if (!iRec) break; // Конец данных iEnd += iRec; } printf("\nreceived %u", iEnd); } main() { WSAStartup( MAKEWORD(1,1), &WSAData ); /* Создать и настроить сокет */ SendSocket = socket(AF_INET, SOCK_STREAM, 0); // IPPROTO_TCP ? /* Законнектитться */ memset(&remoteAddr, 0, sizeof(SOCKADDR_IN)); // Обнуляем remoteAddr.sin_family = AF_INET; remoteAddr.sin_port = htons(80); // Порт remoteAddr.sin_addr.s_addr = inet_addr(ip); // Числовой IP e = connect (SendSocket, (PSOCKADDR) &remoteAddr, sizeof (remoteAddr)); if (e) { printf("\nconnect error %u", WSAGetLastError()); exit(0); } /* Читаем несколько */ getpage("http://www.john.org/index.html"); getpage("http://www.john.org/BlowedUpRealGood.gif"); getpage("http://www.john.org/FrankenMac.gif"); getpage("http://www.john.org/Wireless.gif"); getpage("http://www.john.org/JohnS.gif"); // getpage("http://www.john.org/index.html", 0); // getpage("/BlowedUpRealGood.gif", 1); // getpage("/FrankenMac.gif", 1); // getpage("/Wireless.gif", 1); // getpage("/JohnS.gif", 1); closesocket(SendSocket); WSACleanup(); } Результаты выглядят примерно так: Code (Text): received 2860 received 0 received 0 received 0 received 0 Имена файлов правильные, по отдельности читаются ОК. И на других ip тоже самое. Самое обидное, что лет несколько назад я уже делал что-то подобное, и у меня все получалось. Но исходники пропали. Пните меня - в каком месте туплю?
iamlamer Судя по всему, сервак закрыл соединение после первого ответа. Нужно парсить хидеры, которые он посылает. Скорее всего, там было "Connection: close".
Увы. Вот начало первой странички (правда, это не с www.john.org, а с другого сервака, на котором то же самое). Code (Text): HTTP/1.1 200 OK Date: Wed, 06 Oct 2010 20:05:02 GMT Server: Apache/1.3.34 (Unix) mod_throttle/3.1.2 rus/PL30.22 Last-Modified: Thu, 02 Sep 2010 12:52:42 GMT Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=windows-1251 Vary: accept-charset, user-agent UPD: а вот с www.john.org: Code (Text): HTTP/1.1 200 OK Date: Wed, 06 Oct 2010 20:11:47 GMT Server: Apache/1.3.19 (Unix) DAV/1.0.3 PHP/4.3.1 Last-Modified: Wed, 09 Jun 1999 20:51:45 GMT ETag: "2f0597-9f9-375ed3e1" Accept-Ranges: bytes Content-Length: 2553 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html Везде keep-alive.
Забыл отписаться. Победил, разумеется, еще вчера: создал сокет - обменялся - прибил. Если кому пригодится (в Интернете одни ляля-тополя, а рабочего издохника - чтобы с одного сервера читались несколько страничек сразу - не нашел), то вот. Code (Text): #include <windows.h> #include <alloc.h> #include <string.h> #include <stdio.h> #define MAXMES 0x200 #define MAXBUF 0xffff char get[MAXMES]; // Строка запроса GET char sBuf[MAXBUF]; // Читаемый буфер int iRec, iEnd, i, e; SOCKET SendSocket; WSADATA WSAData; SOCKADDR_IN remoteAddr; ////////////////////////////////// GET + скачка + отображение void getpage(char *pagename, int mode) { /* Создать и настроить сокет */ SendSocket = socket(AF_INET, SOCK_STREAM, 0); // IPPROTO_TCP ? e = connect (SendSocket, (PSOCKADDR) &remoteAddr, sizeof (remoteAddr)); if (e) { printf("\nconnect error %u", WSAGetLastError()); return; } get[0] = 0; strcat(get, "GET "); strcat(get, pagename); strcat(get, " HTTP/1.1\r\n" ); // При 1.0 не работает keep-alive !!! strcat(get, "Accept: */*\r\n" ); strcat(get, "Accept-Encoding: gzip,deflate\r\n"); strcat(get, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)\r\n"); strcat(get, "Host: www.john.org\r\n"); strcat(get, "Connection: Close\r\n"); strcat(get, "\r\n"); strcat(get, ""); e = send( SendSocket, get, strlen(get), 0); if (e==-1) printf("\nsend error %u\n", WSAGetLastError()); else printf("\nsent %u ", e); memset( sBuf, 0, MAXBUF); iEnd = 0; // Обнуляем while (1) { iRec = recv(SendSocket, (LPSTR) sBuf+iEnd, sizeof(sBuf)-iEnd, 0); if (iRec==-1) printf("\nrecv error %u\n", WSAGetLastError()); if (!iRec) break; // Конец данных iEnd += iRec; } printf("\nreceived %u", iEnd); closesocket(SendSocket); } main() { /* Данные для коннекта */ memset(&remoteAddr, 0, sizeof(SOCKADDR_IN)); // Обнуляем remoteAddr.sin_family = AF_INET; remoteAddr.sin_port = htons(80); // Порт remoteAddr.sin_addr.s_addr = inet_addr("64.142.28.160"); // Числовой IP WSAStartup( MAKEWORD(1,1), &WSAData ); getpage("http://www.john.org/index.html", 0); getpage("http://www.john.org/BlowedUpRealGood.gif", 1); getpage("http://www.john.org/FrankenMac.gif", 1); getpage("http://www.john.org/Wireless.gif", 1); getpage("http://www.john.org/JohnS.gif", 1); WSACleanup(); } и Code (Text): sent 213 received 2822 sent 223 received 18799 sent 217 received 19784 sent 215 received 12929 sent 212 received 3032 Для моей задачи скорости обмена вполне хватает и избыточный трафик не напрягает. Но. Это, конечно, моветон и галимая индокитайщина. По хорошему, надо держать сокет живым и коннект открытым, как в начале топика. Пока вроде работает, и буду потихоньку разбираться дальше. Чего же ей, @#$%^& такой, не хватает?
Возможно проблемы были из за этого кода: Code (Text): e = send( SendSocket, get, strlen(get), 0); if (e==-1) printf("\nsend error %u\n", WSAGetLastError()); else printf("\nsent %u ", e); memset( sBuf, 0, MAXBUF); iEnd = 0; // Обнуляем while (1) { iRec = recv(SendSocket, (LPSTR) sBuf+iEnd, sizeof(sBuf)-iEnd, 0); if (iRec==-1) printf("\nrecv error %u\n", WSAGetLastError()); if (!iRec) break; // Конец данных iEnd += iRec; } тк вы делаете send и практически сразу recv, возможно сервер не успевал ответить или еще чего.. Вообщем нужно юзать select или евенты. Ну и в написании сетевых приложений, как правило пользуются WireShark'ом что бы смотреть, отправился ли ваш пакет, ответил ли сервер..
вот небольшой пример с select: Code (Text): fd_set read_s; timeval time_out; time_out.tv_sec = TIMEOUT; time_out.tv_usec = 0; FD_ZERO (&read_s); FD_SET (hSocket,&read_s); if(select (0,&read_s,NULL,NULL,&time_out)!=0) for(time_out.tv_sec=2;;) { ioctlsocket(hSocket,FIONREAD,&iResult); if(iResult < 0 ) { return -1; } else if(iResult == 0) break; *Out=(char*)realloc(*Out,recvbuflen+iResult); recv(hSocket, *Out+recvbuflen, iResult, 0); recvbuflen+=iResult; cout<<"recv: "<<recvbuflen<<"\n"; FD_ZERO (&read_s); FD_SET (hSocket,&read_s); if(select (0,&read_s,NULL,NULL,&time_out)==0) break; } else { cout<<"TIMEOUT\n"; return 0; } правельнее конечно считывать с флагом MSG_PEEK, пока не встретится \r\n\r\n, потом прочитать хидеры, из хидеров взять Content-Length, и считать оставшуюся часть.. Но для ознакомления и так пойдет
Да я думал об этом, пробовал вставлять Sleep-ы. При маленьких задержках никакой разницы, при больших сервер с той стороны рвет коннект по таймауту (ошибка 10053). Спасибо за сырок. Я планировал сочинить что-то подобное, но все мерещилось, что можно проще.