Articole - rețea - tutorial despre scrierea propriului server web

Internetul joacă un rol important în viața noastră. Luăm poștă, află cele mai recente informații, ne prindem pe prietenii noștri prin ICQ. Dar ceea ce este asociat cu cuvântul Internet la majoritatea oamenilor în primul rând? Site-uri. Mulți oameni cu cuvântul "Internet" își amintesc site-urile preferate, iar unele (nu prea avansate) pun un semnal egal între WWW și Internet, deși acesta are multe alte lucruri interesante: e-mail, IRC, rețelele P2P, MUD-uri și așa mai departe. Dar World Wide Web joacă un rol dominant.







WWW se bazează pe Protocolul de transfer HyperText. Trebuie să spun că HTTP poate fi folosit nu numai pentru transferul de site-uri, ci și pentru transferul de orice în orice fel. Cu ajutorul protocolului HTTP, putem descărca, de exemplu, un film lansat recent sau un mp3 proaspăt :). În rețelele p2p, protocolul HTTP este utilizat în acest scop.

În acest tutorial, vom examina cum să scriem un server web simplu. Presupun că sunteți familiarizat cu elementele de bază ale programării winsock și știți cum să creați socket-uri și să vă conectați la ceva :).

Protocolul de bază pentru transferul hipertextului

Ideea HTTP este destul de simplă. Clientul trimite o solicitare serverului, îl examinează și trimite un răspuns corespunzător. Răspunsul poate fi un fișier solicitat, un mesaj care să ateste că nu există un astfel de fișier pe server sau altceva. Structura interogării eșantionului este după cum urmează:

<метод> - tip de cerere. Principalele două sunt GET și POST. Acestea diferă una de alta, în principal prin modul de trimitere a informațiilor suplimentare trimise împreună cu cererea. În acest tutorial, vom lua în considerare numai metoda GET - funcțional este similară cu metoda POST, dar oarecum mai simplă. Despre metoda POST, vă voi spune în a doua parte a acestui tutorial, dacă, desigur, va apărea deloc :).

<\n> - sunt doi octeți 0Dh, 0Ah, fără îndoială, bine cunoscuți tuturor asamblorilor :).

Astfel, am decis asupra metodei. În momentul de față, solicitarea pe care noi (ca client) trebuie să o trimitem serverului arată astfel:

Acum rămâne să înțelegem câmpurile antet. Cu ajutorul lor, clientul transmite informații suplimentare despre el însuși sau natura solicitării. De exemplu, câmpul de antet utilizat destul de des este "User-Agent". Opera, să zicem, trimite următoarele:

User-Agent: Mozilla / 4.0 (compatibil; MSIE 5.0; Windows 98) Opera 6.02 [en]

Iată cum arată acum interogarea noastră:

Trebuie remarcat faptul că, deși aceste câmpuri și alte câmpuri de antet sunt foarte de dorit, dar, strict vorbind, ele nu sunt obligatorii, adică pot să nu fie. De asemenea, vreau să vă atrag atenția asupra faptului că ultimul fișier antet este urmat de _two_ <\n>, nu unul. Acest lucru este important.

Acum, să aruncăm o privire la toate cele de mai sus din punctul de vedere al serverului web (la urma urmei, am fost de gând să scrie un server web, amintiți-vă.)). El așteaptă până când primește o cerere, o procesează și trimite un răspuns care arată cam așa:

După primirea solicitării, serverul trebuie să dea clientului un cod de răspuns (acesta este un număr din trei cifre), precum și un mesaj care îl însoțește. De exemplu, dacă documentul solicitat a fost găsit, primul rând al răspunsului ar fi aproximativ următorul:

Dacă codurile de răspuns sunt specificate rigid de standard (200 înseamnă că cererea a fost procesată cu succes și documentul / informațiile corespunzătoare sunt returnate), atunci <сообщение> depinde doar de imaginația ta (bineînțeles, în sensul că ar trebui să coincidă cu <кодом_ответа>. De exemplu, în loc de "HTTP / 1.1 200 Ok" putem trimite "HTTP / 1.1 200 Vrei, o vei primi" :).







Răspunsul serverului poate avea și câmpuri de antet. Acestea conțin informații suplimentare despre răspuns și datele care vin împreună cu acesta. Apoi, voi da cele mai importante (pentru noi).

Tip de conținut - acest antet specifică tipul de date care trebuie trimise. Cele mai importante tipuri sunt specificate în standard, iar ceea ce scrieți în acest câmp depinde de comportamentul clientului atunci când primiți date. De exemplu, dacă trimiteți un fișier html în browser-ul utilizatorului, trebuie să specificați tipul de text "text / html", altfel browserul poate afișa incorect fișierul sau nu îl poate afișa deloc, dar solicită utilizatorului să îl descarce.

Content-Length - specifică lungimea datelor (fără a include răspunsul în sine cu datele antetului) în octeți.

Pe baza celor de mai sus, răspunsul serverului va arăta astfel:

Dacă vrem să trimitem un simplu fișier html, atunci putem scurta răspunsul la următoarele:

Ca rezultat, obținem următoarele. Clientul trimite o cerere pentru un document care se află, de exemplu, în rădăcina serverului:

Serverul primește această solicitare, o procesează și returnează pagina rădăcină:

"Serverul web", al cărui cod sursă a fost dat mai sus, este foarte primitiv. Știe doar să accepte o solicitare și, fără să o verifice pentru corectitudine, să emită doar o pagină html binevenită.

În http.asm, totul, sper, este destul de ușor de înțeles. Inițializăm prizele, creăm o fereastră (pentru care, vom explica mai târziu), introduceți bucla mesajului și, înainte de a închide aplicația, sunăm WSACleanup.

Cel mai interesant este în http_window.asm. Când procesăm mesajul WM_CREATE, creăm un socket:

Apoi numim următoarea funcție:

Iată ce spune Platforma SDK despre această funcție:

[începe descrierea funcției WSAAsynctSelect]

Funcția WSAAsyncSelect indică Windows să trimită mesaje despre evenimente care afectează un anumit socket.

s - Un mâner la soclu, despre evenimentele asociate cu care, vor fi raportate.

hWnd - Mânerul ferestrei la care vor fi trimise aceste mesaje.

wMsg - Mesajul care trebuie trimis.

lEvent - O mască care specifică evenimentele de interes.

Dacă apelul funcției WSAAsyncSelect a avut succes, valoarea returnată va fi zero. În caz contrar, SOCKET_ERROR va fi returnat și puteți obține codul de eroare apelând WSAGetLastError.

Rețineți că, după ce WSAAsyncSelect vă trimite un mesaj despre un anumit eveniment asociat socketului, până când faceți o acțiune, nu veți primi un mesaj nou despre același eveniment. De exemplu, dacă ați primit mesajul FD_ACCEPT (cineva încearcă să vă contacteze), nu veți primi mesaje despre o altă încercare de conectare până când nu apelați funcția de acceptare.

Specificăm WM_SOCKET, definit în http.asm, ca mesaj care va fi trimis la Windows când apare mesajul care ne interesează. Informațiile necesare vor fi în wParam (mânerul socket-ului cu care este asociat evenimentul) și în lParam (în cuvântul inferior - codul evenimentului).

De fapt, aceste linii conțin răspunsul la modul de a face un server dintr-o aplicație (nu neapărat o rețea web). Aceasta se face prin funcția de ascultare.

[începutul descrierii funcției de ascultare]

Funcția de ascultare stabilește soclul la o stare în care ascultă portul pentru conexiunile primite.

s - Descrierea socketului

backlog - Numărul maxim de conexiuni primite.

Dacă în timpul apelului nu s-a produs nici o eroare, ascultarea va reveni la zero. În caz contrar, valoarea SOCKET_ERROR va fi returnată, iar codul de eroare poate fi recuperat utilizând funcția WSAGetLastError.

A fost primit un mesaj WM_SOCKET. Aceasta înseamnă că a existat un eveniment de interes pentru noi, legat de mufa de ascultare.

Cineva încearcă să se conecteze la serverul nostru web. Apelam funcția de acceptare pentru a permite conexiunea de intrare.

[începe acceptarea descrierii funcției]

Funcția de acceptare permite o conexiune primită.

s - Un mâner socket care a fost plasat anterior în starea de ascultare cu funcția de ascultare. Conexiunea reală se face folosind un soclu, care este returnat prin acceptare.

addrlen - Un indicator opțional cu două cuvinte care conține lungimea addr.

Dacă nu s-a produs nicio eroare, acceptați să readuce mânerul noului soclu, prin care va avea loc conexiunea.

În caz contrar, INVALID_SOCKET va fi returnat și codul de eroare poate fi recuperat utilizând funcția WSAGetLastError.

Dacă soclul a fost închis de client, atunci îl închidem și de partea noastră.

Pentru mai multe informații despre protocolul HTTP, vă recomandăm să consultați RFC 2068.

[C] Aquila / WASM.RU







Trimiteți-le prietenilor: