HTTP klient pomocí BSD socketů
Jedná se o první školní projekt v rámci předmětu počítačové sítě. Zadáním bylo vytvořit jednoduchý HTTP klient v C/C++ a s použitím BSD socketů.
Výchozím textem k implementaci bylo toto RFC, které jsem ovšem rozhodně neměl čas přečíst celé. Implementoval jsem jen nutné minimum (redirect, chunked přenos, základní stavové kódy) pro funkčního HTTP klienta.
S implementací jsem začal v den odevzdávání, takže se prosím nikdo
neinspirujte stylem kódu (vše v main, divná kombinace C a C++). Musím se ale
pochlubit svým prvním použitím goto (mimo asembler)..
Použití programu je jednoduché. Při svém spuštění očekává jediný parametr - platnou url. Podporuje i jiné porty, než výchozí.
$ webclient www.abcd.cz:88/cesta/test.html
Pokud by chtěl někdo tento program vyzkoušet na Windows, tak je to možné s použitím Cygwin, který implementuje sys/socket.h a nebo je možné program portovat na WinSocks. Jsou tam drobné rozdíly, ale nic zásadního.
BSD Sockety
BSD (nebo také Berkley) sockety jsou Unixové API (najdete je tedy nativně v Linuxu nebo BSD) pro meziprocesovou a internetovou komunikaci. Jejich smyslem je obalit systémové implementace jednotlivých protokolů (tj. IPv4, IPv6, TCP, UDP, ...) různých úrovní a vytvořit jednotné rozhraní. Vznikly již roku 1983 a byly natolik úspěšné, že jsou de facto používány ve všech moderních OS. Windows je implementuje mírně odlišně (již zmíněné WinSocks) a v praxi se doporučuje používat POSIX sockety, které nahrazují starší BSD funkce (gethostbyname, gethostbyaddr, ...) za moderní (příjemněji se programují a umí některé věci navíc) gettaddrinfo a getnameinfo.
Tento projekt ukazuje použití původních BSD socketů (testován byl na FreeBSD 10.2, ale funguje i na moderním Linuxu) a IPv4/TCP stacku.
Základní princip
Využití BSD socketů je v zásadě velmi jednoduché. Nejprve vytvoříme tzv. socket - z pohledu programátora jde de facto o "obyčejný soubor" a můžeme s ním pracovat velmi podobně. Když do něj zapíšeme, systém naprosto autonomně vezme data, vytvoří z nich pakety (v tomto případě TCP) a odešle je. Díky použití TCP je zaručeno správné pořadí doručených dat a také jejich bezchybnost.
Vytvoření socketu je triviální. Definujeme, které protokoly budou využity. AF_INET značí IPv4 a SOCK_STREAM TCP:
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
Další krok je opět jednoduchý. Je třeba získat IP adresu serveru z jeho jména (DNS záznamu). K tomu můžeme využít gethostbyname().
struct hostent *server; server = gethostbyname(hostname.c_str()); // očekává klasický C string
Ze struktury hostent pak získáme všechny důležité informace. Tento krok je poněkud neprůhledný a při použití zmíněných POSIX socketů (ty jsem využil v druhém projektu) odpadá.
struct sockaddr_in server_address; memset(&server_address, 0, sizeof(server_address)); // vymazání struktury server_address.sin_family = AF_INET; // nastavení IPv4 memcpy(&server_address.sin_addr.s_addr, server->h_addr_list[0], server->h_length); // nakopírování samotné adresy server_address.sin_port = htons(port); // htons: převod do big-endian
Dalším krokem je již připojení k serveru:
connect(tcp_socket, (const struct sockaddr *) &server_address, sizeof(server_address));
Teď, když máme navázáno TCP spojení, můžeme jednoduše odesílat a přijímat data..
string http_get = "nejaky text podle HTTP standardu.."; int reply_size; char reply[BUFFER_LEN]; send(tcp_socket, http_get.c_str(), http_get.size(), 0); reply_size = recv(tcp_socket, reply, BUFFER_LEN, 0);
Pokud vám vrtala hlavou ta nula jako poslední parametr všech volání, tak jde o flags - můžete modifikovat chování (možnosti viz. manuálové stránky). V tomto případě například bude program čekat, až bude přijato přesně chunk_size bajtů a až pak je vrátí.
reply_size = recv(tcp_socket, reply, chunk_size, MSG_WAITALL);
Na závěr po sobě jakožto slušní programátoři uklidíme:
close(tcp_socket);
Závěr
Program je jen velmi jednoduchá ukázka, jak vytvořit aplikaci komunikující po síti. Příště ukážu, jak vytvořit server a vlastní jednoduchý protokol pro přenos souborů.
Galerie

Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 47x (3.5 kB)
Aplikace je včetně zdrojových kódů v jazyce C