Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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).. :D

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

Program byl vytvořen v roce 2016.

 

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 44x (3.5 kB)
Aplikace je včetně zdrojových kódů v jazyce C

 

Všechny články v sekci
Zdrojákoviště jazyka C - Programování v Linuxu
Program pro vás napsal David Novák
Avatar
Uživatelské hodnocení:
2 hlasů
Autor se zajímá především o nízkoúrovňové programování (C/C++, ASM) a návrh hardwaru (VHDL).
Aktivity