Listopad 21 2009 02:26:17
Nawigacja
Strona g³ówna
O nas
Artyku³y
Partnerzy
Poczajowo
Forum
Szukaj
Zlecenia i propozycje
Ostatnie artyku³y
[C++] Prosty czat w Qt4
MemoryError/Memory E...
Test na cz³owieczeñstwo
Wysy³anie danych met...
Delphi i CGI
Aktualnie online
Go¶ci online: 1

U¿ytkowników online: 1
Magnefikko

£±cznie u¿ytkowników: 56
Najnowszy u¿ytkownik: KangurX
Informacje
Posty na forum: 2711
Tematy na forum: 133
Artyku³y: 65
Komentarze: 125
Oceny: 68
Hosting
[C++] Pobieranie strony internetowej
Dobry ;)

W dzisiejszym odcinku zajmiemy siê pobieraniem zawarto¶ci strony internetowej metod± GET dziêki programowi napisanemu w C++. Jako interfejs pos³u¿± nam sockety (Linux)/winsock (Windows).

1. Request - co i jak?
Request to po prostu ¿±danie wys³ane przez przegl±darkê serwerowi http. Przyk³adowy request:
GET /axe/news.php HTTP/1.1
Host: promhyl.netne.net

Naszym zadaniem jest wys³aæ w³a¶nie takie ¿±danie podanemu serwerowi http.
Zatem bierzmy siê do roboty.
Ma³a uwaga co do ¿±dania: ka¿da linia koñczy siê znakami \r\n. Ostatnia zawiera dwie takie kombinacje, aby serwer wiedzia³ gdzie koñczy siê request.

2. Kod.
Kod bêdzie dla Windowsa jak i dla Linuksa. Jako, ¿e ró¿nic wielu nie ma pos³u¿ymy siê instrukcjami preprocesora, aby kompilator wybra³ odpowiedni kod. Dla uproszczenia napiszemy sobie ma³± klasê odpowiadaj±c± za zarz±dzanie urlem.

// getwww.cpp
// Kompilacja:
// Linux:
// g++ getwww.cpp -o getwww
// Windows:
// g++ getwww.cpp -o getwww -lws2_32

// Tutaj definiujemy symbol, który pos³u¿y kompilatorowi do wybrania
// odpowiednich nag³ówków. Wystarczy jeden sybmol. Jako, ¿e piszê pod Linuksem
// zostawiê go zakomentowanego. Je¶li kto¶ pisze pod Windowsem, nale¿y go
// odkomentowaæ.

// #define WINDOWS

#include < iostream>
#include < fstream>
#include < ctime>
#include "url.cpp"

// Nag³ówki dla Windowsa
#ifdef WINDOWS
#include < winsock2.h>

// Nag³ówki dla Linuksa
#else
#include < sys/socket.h>
#include < sys/stat.h>
#include < netinet/in.h>
#include < arpa/inet.h>
#include < netdb.h>
// Przera¿aj±ce nie? xD
// W cale nie. Wystarczy w manualu wpisaæ i od razu podane gdzie to jest.
#endif

using namespace std;

// Prototypy //////////////////////////////////////////////////////////////////
void usage(const char* progname);
void wait(unsigned int sec);

// MAIN ///////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
// Argumenty:
// argv[0] - nazwa programu
// argv[1] - url
// argv[2] - plik wynikowy

if (argc != 3)
{
usage(argv[0]);
return 0;
}

Url url(argv[1]);
if (!url.isValid())
{
cout << "Podany url jest nieprawidlowy!\n";
return -1;
}

cout << "Url: " << url.getUrl() << endl;
cout << "Www: " << url.getWww() << endl;
cout << "Host: " << url.getHost() << endl;
cout << "File: " << url.getFile() << endl;

ofstream file(argv[2]);
if (!file)
{
cout << "Nie mozna otworzyc pliku do zapisu!\n";
return -1;
}

// Je¶li jeste¶my pod Windowsem - inicjalizujemy WinSocka
#ifdef WINDOWS
WSAData wd;
if (WSAStartup(MAKEWORD(2,0), &wd) == SOCKET_ERROR)
{
cout << "Nie udalo sie zainicjalizowac biblioteki WinSock!\n";
return -1;
}
#endif

// Tworzymy socketa
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// Pobieramy adres hosta
hostent* host = gethostbyname(url.getHost());
if (!host)
{
cout << "Nie odnaleziono podanego hosta!\n";
return -1;
}

sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr = *(in_addr*)host->h_addr;

cout << "IP serwera: " << inet_ntoa(addr.sin_addr) << endl;

// £±czymy z serwerem
if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == -1)
{
cout << "Nie udalo sie nawiazac polaczenia z serwerem!\n";
return -1;
}

// ¦lemy requesta
string request = "GET ";
request += url.getFile();
request += " HTTP/1.1\r\nHost: ";
request += url.getWww();
request += "\r\n\r\n";

cout << "Request: " << request;

send(sock, request.c_str(), request.length(), 0);

// Odbieramy odpowied¼.
char buffer[8192];
int size;

do
{
wait(2); // Czekamy, aby wszystkie dane nap³ynê³y.
size = recv(sock, buffer, sizeof(buffer), 0);
cout << "Odebrano " << size << " B danych.\n";
file.write(buffer, size);
}while (size == sizeof(buffer));

file.close();

close(sock); // Zamykamy po³±czenie

#ifdef WINDOWS
WSACleanup();
#endif

cout << "Zakonczono.\n";

return 0;
}

// usage //////////////////////////////////////////////////////////////////////
void usage(const char* progname)
{
cout << "Uzycie:\n";
cout << "\t\t" << progname << " \n\n";
cout << "\tadres url - adres do strony, ktora chcesz pobrac \n\t\t(np. http://www.promhyl.netne.net/)\n";
cout << "\tplik wynikowy - do tego pliku zostanie zapisana pobrana strona\n\n";
}

// wait ///////////////////////////////////////////////////////////////////////
void wait(unsigned int sec)
{
// Ta funkcja s³u¿y do opó¼nienia odbioru danych od serwera, aby wszystkie mog³y nap³yn±æ do socketa.
time_t a = time(NULL) + sec;
while (a > time(NULL));
}


Pliki url.h i url.cpp do³±czone s± do archiwum z kodem. My¶lê, ¿e wszystko jest dobrze obkomentowane ;)

Program ten ma kilka s³abo¶ci, m.in. czas wyznaczony na doj¶cie danych mo¿e siê wyd³u¿yæ, program nie ucina nag³ówków itp., ale dzia³a jak nale¿y ;)

3. Materia³y do pobrania.
Kompletny kod, oraz skompilowany program (pod Linuksem) - tutaj.

4. Epilog.
No to by by³o na tyle. Pozdrowienia dla Promhyl Studies, a w szczególno¶ci dla Widma ;P


Pozdrawiam
Sinis
Komentarze
#1 | widmo dnia
dziêkuwa ;**
#2 | Sinis dnia
Plo¶¶ ;*
Dodaj komentarz
Zaloguj siê, aby móc dodaæ komentarz.
Oceny
Tylko zarejestrowani u¿ytkownicy mog± oceniaæ zawarto¶æ strony

Zaloguj siê lub zarejestruj, ¿eby móc zag³osowaæ.

¦wietne! ¦wietne! 100% [1 g³os]
Bardzo dobre Bardzo dobre 0% [Brak oceny]
Dobre Dobre 0% [Brak oceny]
¦rednie ¦rednie 0% [Brak oceny]
S³abe S³abe 0% [Brak oceny]
Logowanie
Nazwa u¿ytkownika

Has³o



Nie masz jeszcze konta?
Zarejestruj siê

Nie mo¿esz siê zalogowaæ?
Popro¶ o nowe has³o
Shoutbox
Musisz zalogowaæ siê, aby móc dodaæ wiadomo¶æ.

21/11/2009 02:13
Carcass rot 'n' roll Hacking Cover: "let's root!"

21/11/2009 01:51
To nie to co my¶lisz!

21/11/2009 01:43
Game Over Jazz, hell yeah! FUCK YOU ALL!

21/11/2009 01:38
Scatman to Bóg, Norther to Jezus, ACS to Duch ¦wiêty, Coma to Rydzyk.

21/11/2009 01:30
Otwarta zdrada.

21/11/2009 01:12
<333 xD

21/11/2009 01:08
Dziêki wielkie Sin ;* xd

21/11/2009 01:05
Nie jestem pewny co do parametru, ale chyba tak.

21/11/2009 01:05
fflush(stdin/stdou
t);

21/11/2009 01:03
Dobranoc. Mam krótkie pytanie, a w zasadzie pro¶bê- powiedzcie mi prosze jaki jest odpowiednik cin.clear w jêzyku c Smile

by Sinis & Magnefikko