Contacte

Programare în rețea - TCP. Aplicație client-server pe o priză de flux TCP Fluxuri de date de intrare și ieșire

Servere care implementează aceste protocoale în rețea corporativă oferiți clientului o adresă IP, un gateway, o mască de rețea, servere de nume și chiar o imprimantă. Utilizatorii nu trebuie să își configureze manual gazdele pentru a utiliza rețeaua.

Sistemul de operare QNX Neutrino implementează un alt protocol plug-and-play numit AutoIP, care este o schiță a IETF reglare automată... Acest protocol este utilizat în rețelele mici pentru a atribui adrese IP gazdelor care sunt link-locale. Protocolul AutoIP determină în mod independent adresa IP locală a canalului, utilizând o schemă de negociere cu alte gazde și fără a contacta un server central.

Utilizarea PPPoE

PPPoE înseamnă Protocolul Point-to-Point prin Ethernet. Acest protocol încapsulează date pentru transmisie printr-o rețea Ethernet cu punte.

PPPoE este o specificație de conectare a utilizatorului Rețele Ethernet la Internet printr-o conexiune în bandă largă, cum ar fi o linie închiriată, un dispozitiv wireless sau un modem prin cablu. Utilizarea protocolului PPPoE și a modemului în bandă largă oferă utilizatorilor servicii locale rețea de calculatoare acces autentificat individual la rețele de date de mare viteză.

PPPoE combină tehnologia Ethernet cu PPP pentru a crea în mod eficient o conexiune separată la un server la distanță pentru fiecare utilizator. Controlul accesului, contabilitatea conexiunii și selectarea furnizorului de servicii sunt specifice utilizatorului, nu specifice gazdei. Avantajul acestei abordări este că nici compania de telefonie, nici furnizorul de servicii de Internet nu trebuie să ofere asistență specială în acest sens.

Spre deosebire de conexiunile dial-up, conexiunile DSL și modemul prin cablu sunt întotdeauna active. Deoarece conexiunea fizică la un furnizor de servicii la distanță este partajată de mai mulți utilizatori, este necesară o metodă de contabilitate care să înregistreze expeditorii și destinațiile traficului și să taxeze utilizatorii. PPPoE permite unui utilizator și unei gazde la distanță care participă la o comunicare să învețe reciproc adresele de rețea în timpul unui schimb inițial numit detectare(descoperire). După o sesiune între un utilizator individual și nod la distanță(de exemplu, de către ISP-ul dvs.) este setat, această sesiune poate fi monitorizată pentru încărcare. În multe case, hoteluri și corporații, accesul la Internet este partajat pe linii digitale de abonați folosind Ethernet și PPPoE.

O conexiune PPPoE constă dintr-un client și un server. Clientul și serverul funcționează folosind orice interfață apropiată de specificațiile Ethernet. Această interfață este utilizată pentru a emite adrese IP clienților cu legarea acestor adrese IP la utilizatori și, opțional, la stații de lucru, în loc doar de autentificare stație de lucru... Serverul PPPoE creează o conexiune punct-la-punct pentru fiecare client.

Stabilirea unei sesiuni PPPoE

Pentru a crea o sesiune PPPoE, ar trebui să utilizați serviciulpppoed... Modulio-pkt- * nOferă servicii de protocol PPPoE. Mai întâi trebuie să alergiio-pkt- *cușofer potrivit... Exemplu:

Aplicație client-server pe soclu de transmisie TCP

În exemplul următor, folosim TCP pentru a furniza fluxuri de octeți bidirecționale ordonate și fiabile. Să construim o aplicație completă care include un client și un server. Mai întâi demonstrăm cum să construim un server pe socket-uri de streaming TCP și apoi o aplicație client pentru a testa serverul nostru.

Următorul program creează un server care primește solicitări de conectare de la clienți. Serverul este construit sincron, prin urmare, execuția firului este blocată până când serverul acceptă să se conecteze la client. Această aplicație demonstrează un server simplu care răspunde unui client. Clientul încheie conexiunea prin trimiterea unui mesaj către server .

Server TCP

Crearea structurii serverului este prezentată în următoarea diagramă funcțională:

Iată codul complet pentru programul SocketServer.cs:

// SocketServer.cs folosind System; folosind System.Text; folosind System.Net; folosind System.Net.Sockets; namespace SocketServer (class Program (static void Main (string args)) (// Setați punctul final pentru socketul IPHostEntry ipHost = Dns.GetHostEntry ("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = new IPEndPoint (ipAddr, 11); // Creați un socket Tcp / Ip sListener = socket nou (ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Atribuiți socketul la punctul final local și ascultați socket-urile primite încercați (sListener.Bind (ipEndPoint ); sListener. Ascultați (10); // Începeți să ascultați conexiunile în timp ce (adevărat) (Console.WriteLine („Se așteaptă o conexiune pe port (0)”, ipEndPoint); // Programul se întrerupe, așteptând o conexiune de intrare Socket handler = sListener.Accept (); șir de date = nul; // Am așteptat un client care încearcă să se conecteze cu noi octeți octeți = octet nou; int bytesRec = handler.Receive (octeți); date + = Codificare.UTF8.GetString (bytes, 0, bytesRec); // Afișează date pe consolă Console.Write („Received text: "+ date +" \ n \ n "); // Trimiteți un răspuns clientului \ string reply = "Vă mulțumim pentru cererea din" + data.Length.ToString () + "caractere"; byte msg = Encoding.UTF8.GetBytes (răspuns); handler.Send (msg); if (data.IndexOf (" ")> -1) (Console.WriteLine (" Serverul a încheiat conexiunea cu clientul. "); Break;) handler.Shutdown (SocketShutdown.Both); handler.Close ();)) catch (Exception ex) (Console.WriteLine (ex.ToString ());) în cele din urmă (Console.ReadLine ();))))

Să aruncăm o privire asupra structurii acestui program.

Primul pas este de a stabili un punct final local pentru socket. Înainte de a deschide un soclu pentru a asculta conexiunile, trebuie să pregătiți o adresă locală a punctului final. Adresa unică a serviciului TCP / IP este determinată de combinația adresei IP a gazdei cu numărul portului de serviciu care creează punctul final al serviciului.

Clasa Dns oferă metode care returnează informații despre adresele de rețea acceptate de dispozitiv în retea locala... Dacă un dispozitiv LAN are mai multe adrese de rețea, clasa Dns returnează informații despre toate adresele de rețea, iar aplicația trebuie să selecteze o adresă adecvată din matrice pentru a fi difuzată.

Creați un IPEndPoint pentru server prin combinarea primei adrese IP a gazdei din metoda Dns.Resolve () cu numărul portului:

IPHostEntry ipHost = Dns.GetHostEntry ("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = IPEndPoint nou (ipAddr, 11000);

Aici clasa IPEndPoint reprezintă localhost pe portul 11000. Apoi, creați un socket de flux cu o nouă instanță a clasei Socket. Cu un punct final local configurat pentru a asculta conexiunile, se poate crea un socket:

Socket sListener = socket nou (ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

Enumerare AdresaFamilie specifică schemele de adresare pe care o instanță din clasa Socket le poate folosi pentru a rezolva o adresă.

În parametru SocketType există socketuri TCP și UDP. În acesta, puteți defini, printre altele, următoarele valori:

Dgram

Suportă datagrame. Valoarea Dgram necesită să specificați Udp pentru tipul de protocol și InterNetwork în parametrul familiei de adrese.

Brut

Sprijină accesul la protocolul de transport subiacent.

Curent

Suportă prize de streaming. Valoarea Stream necesită specificarea Tcp pentru tipul de protocol.

Al treilea și ultimul parametru definește tipul de protocol necesar pentru socket. În parametru ProtocolType puteți specifica următoarele valori cele mai importante - Tcp, Udp, Ip, Raw.

Următorul pas ar trebui să fie atribuirea soclului folosind metoda Bind ()... Când un socket este deschis de constructor, nu i se atribuie niciun nume, doar un descriptor este rezervat. Metoda Bind () este apelată pentru a atribui un nume soclului serverului. Pentru ca socket-ul clientului să poată identifica socket-ul de transmisie TCP, programul server trebuie să numească socket-ul său:

SListener.Bind (ipEndPoint);

Metoda Bind () leagă soclul de punctul final local. Trebuie să apelați metoda Bind () înainte de orice încercare de a apela metodele Listen () și Accept ().

Acum, după ce ați creat un socket și i-ați asociat un nume, puteți asculta mesajele primite folosind metoda Asculta ()... Într-o stare de ascultare, soclul va aștepta încercările de conectare primite:

SListener.Listen (10);

Parametrul definește restante indicând număr maxim conexiuni în așteptare în coadă. În codul dat, valoarea parametrului permite să se acumuleze până la zece conexiuni în coadă.

În starea de ascultare, trebuie să fiți gata să consimțiți la conexiunea cu clientul, pentru care este utilizată metoda Accept ()... Această metodă obține o conexiune client și finalizează asocierea nume client / server. Metoda Accept () blochează firul apelantului până când ajunge o conexiune.

Metoda Accept () preia prima cerere de conexiune din coada de solicitări în așteptare și creează un nou socket pentru a o gestiona. Deși este creat un nou socket, socketul original continuă să asculte și poate fi multithread pentru a primi mai multe solicitări de conexiune de la clienți. Nicio aplicație de server nu ar trebui să închidă soclul de ascultare. Ar trebui să funcționeze în continuare alături de soclurile create de metoda Accept pentru a gestiona cererile primite ale clienților.

While (true) (Console.WriteLine ("Așteptarea unei conexiuni pe port (0)", ipEndPoint); // Programul se întrerupe, așteptând o conexiune de intrare Socket handler = sListener.Accept ();

Odată ce clientul și serverul au stabilit o conexiune între ei, puteți trimite și primi mesaje folosind metodele Trimite ()și A primi () Clasa soclu.

Metoda Send () scrie datele de ieșire în socketul la care este stabilită conexiunea. Metoda Receive () citește datele primite pe un socket de flux. Când utilizați un sistem bazat pe TCP, trebuie stabilită o conexiune între socketuri înainte de a executa metodele Send () și Receive (). Protocolul exact dintre cele două entități care interacționează trebuie determinat din timp, astfel încât aplicațiile client și server să nu se blocheze reciproc, neștiind cine ar trebui să trimită mai întâi datele lor.

Când se finalizează schimbul de date între server și client, trebuie să închideți conexiunea folosind metodele Închide ()și Închide ():

Handler.Shutdown (SocketShutdown.Both); handler.Close ();

SocketShutdown este o enumerare care conține trei valori de oprit: Ambii- oprește trimiterea și primirea de date prin soclu, A primi- nu mai primește date pe soclu și Trimite- oprește transmiterea datelor de către soclu.

Socketul este închis când se apelează metoda Close (), care setează și proprietatea Connected a socketului la false.

Client pe TCP

Funcțiile utilizate pentru a crea o aplicație client seamănă mai mult sau mai puțin cu o aplicație server. Ca și în cazul serverului, aceleași metode sunt folosite pentru a determina punctul final, instanția socketului, trimiterea și primirea de date și închiderea socketului.

Călătorind prin protocoale de rețea.

TCP și UDP sunt ambele protocoale de strat de transport. UDP este un protocol fără conexiune cu livrare de pachete negarantată. TCP (Transmission Control Protocol) este un protocol orientat spre conexiune cu livrare de pachete garantată. Mai întâi există o strângere de mână (Bună. | Bună. | Hai să discutăm? | Haide.), După care conexiunea este considerată stabilită. Mai mult, pachetele sunt trimise înainte și înapoi prin această conexiune (există o conversație) și cu o verificare dacă pachetul a ajuns la destinatar. Dacă pachetul este pierdut sau a sosit, dar cu o sumă de verificare, atunci acesta este trimis din nou („repetare, nu am auzit”). Astfel, TCP este mai fiabil, dar este mai complex din punct de vedere al implementării și, în consecință, necesită mai mult ceas / memorie, ceea ce nu este cel mai puțin important pentru microcontrolere. Exemple de protocoale de aplicații care utilizează TCP includ FTP, HTTP, SMTP și multe altele.

TL; DR

HTTP (Hypertext Transfer Protocol) este un protocol de aplicație prin care serverul trimite pagini către browserul nostru. HTTP este acum omniprezent pe World Wide Web pentru a prelua informații de pe site-uri web. Imaginea arată o lumină pe un microcontroler cu un sistem de operare la bord, în care culorile sunt setate prin browser.

Protocolul HTTP este textual și destul de simplu. De fapt, așa arată Metoda GET trimis de utilitarul netcat la adresa locală IPv6 a serverului bulb:

~ $ nc fe80 :: 200: e2ff: fe58: b66b% mazko 80<

Metoda HTTP este de obicei un cuvânt englezesc scurt, cu majuscule, care face sensibilitate la majuscule și minuscule. Fiecare server trebuie să accepte cel puțin metodele GET și HEAD. În plus față de metodele GET și HEAD, sunt adesea folosite metodele POST, PUT și DELETE. Metoda GET este utilizată pentru a solicita conținutul resursei specificate, în cazul nostru aici este GET / b HTTP / 1.0 unde calea / b este responsabilă de culoare (albastru). Răspuns server:

HTTP / 1.0 200 OK Server: Contiki / 2.4 http://www.sics.se/contiki/ Conexiune: închidere Cache-Control: fără cache, fără magazin, trebuie revalidat Pragma: fără cache Expiră: 0 Conținut- tip: text / html Contiki RGB

Roșul este OPRIT

Verde este OPRIT

Albastrul este ACTIVAT

Codul de stare (avem 200) face parte din prima linie a răspunsului serverului. Este un număr întreg din trei cifre. Prima cifră indică clasa afecțiunii. Codul de răspuns este de obicei urmat de o frază explicativă în limba engleză, separată de un spațiu, care explică persoanei motivul acestui răspuns special. În cazul nostru, serverul a funcționat fără erori, totul într-o grămadă (OK).

Atât cererea, cât și răspunsul conțin anteturi (fiecare linie este un câmp de antet separat, perechea nume-valoare este separată de două puncte). Anteturile se termină cu o linie goală, după care datele pot merge.

Browserul meu refuză să deschidă adresa IPv6 locală, astfel încât o adresă suplimentară este scrisă în firmware-ul microcontrolerului și același prefix trebuie de asemenea atribuit interfeței de rețea virtuală a simulatorului:

~ $ sudo ip addr add abcd :: 1/64 dev mazko # linux ~ $ netsh interface ipv6 set address mazko abcd :: 1 # windows ~ $ curl http: //



TCP se integrează în mod natural în mediul client / server (vezi Figura 10.1). Aplicație server ascultă(ascultați) solicitări de conexiune primite. De exemplu, serviciile WWW, File Transfer sau Terminal Access ascultă cererile clienților. Comunicațiile în TCP sunt inițiate de rutine adecvate care inițiază conexiunea la server (vezi capitolul 21 de pe interfața de programare a socketului).

Orez. 10.1. Clientul apelează serverul.

În realitate, clientul poate fi un alt server. De exemplu, serverele de e-mail se pot conecta la alte servere de e-mail pentru a redirecționa mesaje de e-mail între computere.

10.2 Concepte TCP

În ce formă ar trebui aplicațiile să trimită date prin TCP? Cum transferă TCP datele către IP? Cum identifică protocoalele TCP de trimitere și primire conexiunea dintre aplicații și elementele de date necesare pentru implementarea acesteia? La toate aceste întrebări se răspunde în secțiunile următoare, care descriu concepte TCP de bază.

10.2.1 Fluxuri de date de intrare și ieșire

Conceptual modelul de conexiune presupune că aplicația trimite un flux de date către aplicația peer. În același timp, este capabil să primească un flux de date de la partenerul său de conexiune. TCP oferă full duplex(full duplex) mod de operare în care simultan două pâraie date (vezi Figura 10.2).


Orez. 10.2. Aplicațiile schimbă fluxuri de date.

10.2.2 Segmente

TCP poate transforma fluxul de date lăsând aplicația într-un formular adecvat pentru plasarea în datagrame. Cum?

Aplicația transmite date în TCP, iar acest protocol le introduce tampon de ieșire(trimiteți tampon). Apoi, TCP taie bucăți de date din buffer și le trimite, adăugând un antet (în acest caz, segmente- segment). În fig. 10.3 arată modul în care datele din tampon de ieșire TCP este împachetat în segmente. TCP transmite segmentul către IP pentru livrare ca o datagramă separată. Ambalarea datelor în bucăți de lungimea corectă asigură transmiterea eficientă a datelor, așa că TCP va aștepta până când cantitatea corespunzătoare de date apare în bufferul de ieșire înainte de a crea un segment.


Orez. 10.3 Crearea unui segment TCP

10.2.3 Ejecție

Cu toate acestea, cantități mari de date sunt adesea imposibil de aplicat aplicațiilor din lumea reală. De exemplu, atunci când un program client de utilizator final inițiază o sesiune interactivă cu server la distanta, apoi utilizatorul introduce doar comenzi (urmate de apăsarea tastei Întoarcere).

Programul client al utilizatorului are nevoie de TCP pentru a afla despre trimiterea datelor către gazda la distanță și pentru a face acest lucru imediat. În acest caz, utilizați ejecție(Apăsați).

Dacă te uiți la operațiuni într-o sesiune interactivă, poți găsi multe segmente cu puține date și, în plus, găurile pot fi găsite în aproape fiecare segment de date. Cu toate acestea, push nu ar trebui aplicat în timpul transferurilor de fișiere (cu excepția ultimului segment), iar TCP va putea împacheta cel mai eficient datele în segmente.

10.2.4 Date urgente

Modelul de redirecționare a aplicației presupune aplicarea unui flux ordonat de octeți care se deplasează la destinație. Referindu-ne din nou la exemplul sesiunii interactive, să presupunem că utilizatorul a apăsat tasta Atenţie(atenție) sau pauză(întrerupe). Aplicația de la distanță trebuie să poată sări peste octeți care interferează și să răspundă la apăsarea tastei cât mai curând posibil.

Mecanism date urgente(date urgente) marchează informațiile speciale din segment ca urgent. Prin aceasta, TCP își informează colegul că segmentul conține date urgente și poate indica unde se află. Partenerul ar trebui să transmită aceste informații aplicației de destinație cât mai curând posibil.

10.2.5 Porturi de aplicație

Clientul trebuie să identifice serviciul pe care dorește să îl acceseze. Acest lucru se face prin specificarea adresei IP a serviciului gazdei și a numărului său de port TCP. La fel ca în cazul UDP, numerele de port TCP variază de la 0 la 65535. Porturile cuprinse între 0 și 1023 sunt denumite cunoscute și sunt utilizate pentru a accesa serviciile standard.

Mai multe exemple de porturi bine cunoscute și aplicațiile corespunzătoare ale acestora sunt prezentate în Tabelul 10.1. Servicii Aruncați(portul 9) și chargen(portul 19) sunt versiunile TCP ale serviciilor pe care le cunoaștem deja de la UDP. Amintiți-vă că traficul portului TCP 9 este complet izolat de traficul portului UDP 9.


Tabelul 10.1 Porturi TCP cunoscute în mod obișnuit și aplicațiile lor corespunzătoare

Port Cerere Descriere
9 Aruncați Anularea tuturor datelor primite
19 Chargen Generator de simboluri. Schimb de flux de caractere
20 FTP-Date Port de redirecționare a datelor FTP
21 FTP Port pentru conversație FTP
23 TELNET Port pentru înregistrarea Telnet la distanță
25 SMTP Port SMTP
110 POP3 Preluarea serviciului de poștă electronică pentru computerele personale
119 NNTP Acces la știri online

Dar porturile utilizate de clienți? În cazuri rare, clientul nu lucrează printr-un port bine cunoscut. Dar în astfel de situații, dorind să deschidă o conexiune, solicită adesea sistemului de operare să îi atribuie un port neutilizat și fără rezerve. La sfârșitul conexiunii, clientul este obligat să returneze acest port înapoi, după care portul poate fi reutilizat de un alt client. Deoarece există mai mult de 63.000 de porturi TCP în grupul de numere fără rezerve, limitele porturilor clientului pot fi ignorate.

10.2.6 adrese socket

După cum știm deja, se numește combinația de adresă IP și port pentru comunicații priză. O conexiune TCP este complet identificată prin adresa de soclu la fiecare capăt al acelei conexiuni. În fig. 10.4 arată conexiunea dintre un client la socket (128.36.1.24, port = 3358) și un server la socket (130.42.88.22, port = 21).

Orez. 10.4. Adrese de soclu

Fiecare antet datagram conține adresele IP sursă și destinație. Se va vedea mai târziu că numerele portului sursă și destinație sunt indicate în antetul segmentului TCP.

De obicei, un server este capabil să gestioneze mai mulți clienți în același timp. Adresele de socket unice ale unui server sunt atribuite simultan tuturor clienților săi (vezi Figura 10.5).


Orez. 10.5. Mai mulți clienți conectați la adresele de socket ale serverului

Deoarece datagrama conține un segment de conexiune TCP identificat prin adrese IP și porturi, este foarte ușor pentru un server să țină evidența mai multor conexiuni client.

10.3 Mecanismul de fiabilitate TCP

În această secțiune, vom analiza mecanismul TCP utilizat pentru a furniza date în mod fiabil, menținând în același timp ordinea de redirecționare și evitând pierderea sau duplicarea.

10.3.1 Numerotare și confirmare

TCP folosește numerotarea și confirmarea (ACK) pentru a asigura un transfer de date fiabil. Schema de numerotare TCP este oarecum neobișnuită: fiecare conexiune redirecționată octet este considerat ca având un număr secvențial. Antetul segmentului TCP conține numărul de ordine primul octet de date al acestui segment.

Destinatarul este obligat să confirme primirea datelor. Dacă niciun ACK nu ajunge în intervalul de expirare, datele sunt retransmise. Această metodă se numește confirmare pozitivă cu releu(confirmare pozitivă cu retransmisie).

Receptorul TCP monitorizează îndeaproape numerele de secvență primite pentru a se asigura că datele sunt primite în mod consecvent și că nu există părți lipsă. Deoarece ACK poate fi pierdut aleatoriu sau întârziat, segmentele duplicate pot ajunge la destinatar. Numerele de secvență vă permit să identificați datele duplicate care sunt apoi aruncate.

În fig. 10.6 arată o privire simplificată asupra expirării și retransmiterii TCP.


Orez. 10.6. Timeout și retransmisie în TCP

10.3.2 Port, secvență și câmpuri ACK în antetul TCP

Așa cum se arată în fig. 10.7, primele câmpuri ale antetului TCP oferă spațiu pentru porturile sursă și destinație, numărul secvenței primului octet de date încorporate și un ACK egal cu numărul secvenței Următorul octet așteptat la celălalt capăt. Cu alte cuvinte, dacă TCP primește toți octeții până la 30 de peer, acest câmp va avea o valoare de 31, indicând segmentul de redirecționat.


Orez. 10.7. Valorile inițiale în câmpurile antet TCP

Trebuie remarcat un mic detaliu. Să presupunem că TCP a trimis octeți de la 1 la 50 sau mai mult, nu există date de trimis. Dacă datele sunt primite de la un partener, TCP este obligat să confirme primirea, pentru care va trimite un antet fără date conectate la acesta. Bineînțeles, acest antet conține valoarea ACK. Câmpul secvenței conține valoarea 51, adică numărul următorului octet care intenționează trimite TCP. Când TCP trimite următoarele date, noul antet TCP va avea, de asemenea, o valoare de 51 în câmpul secvenței.

10.4 Stabilirea unei conexiuni

Cum se conectează cele două aplicații? Înainte de comunicare, fiecare dintre ei apelează un subrutină pentru a forma un bloc de memorie care va fi utilizat pentru a stoca parametrii TCP și IP ai acestei conexiuni, de exemplu, adresele de socket, numărul secvenței curente, valoarea inițială a duratei de viață etc.

Aplicația server așteaptă să apară un client care, dorind să acceseze serverul, emite o cerere compus(conectare) identificarea adresei IP și a portului serverului.

Există o particularitate tehnică. Fiecare parte începe numerotarea fiecărui octet nu cu unul, ci cu numărul secvenței aleatorii(mai târziu vom afla de ce se face acest lucru). Specificația originală recomandă: generați un număr de secvență inițial pe baza unui temporizator extern de 32 de biți care crește aproximativ la fiecare 4 μs.

10.4.1 Script de conexiune

Procedura de conectare este adesea denumită o strângere de mână în trei direcții, deoarece sunt schimbate trei mesaje - SYN, SYN și ACK - pentru a stabili o conexiune.

În timpul configurării conexiunii, partenerii schimbă trei informații importante:

1. Cantitatea de spațiu tampon pentru primirea datelor

2. Cantitatea maximă de date transportată în segmentul de intrare

3. Numărul secvenței de pornire utilizat pentru datele de ieșire

Rețineți că fiecare dintre părți aplică operațiunile 1 și 2 pentru a indica limitele în care va opera cealaltă parte. Un computer personal poate avea un buffer de recepție mic, iar un supercomputer poate avea un buffer imens. Structura memoriei unui computer personal poate limita porțiunile de date primite la 1 KB, iar supercomputerul este controlat cu segmente mari.

Capacitatea de a controla modul în care cealaltă parte trimite date este o proprietate importantă pentru scalabilitatea TCP / IP.

În fig. 10.8 arată un exemplu de script de conexiune. Sunt prezentate numere secvențiale inițiale foarte simple pentru a nu copleși desenul. Rețineți că în această figură, clientul poate primi segmente mai mari decât serverul.


Orez. 10.8. Stabilirea unei conexiuni

Se efectuează următoarele operații:

1. Serverul este inițializat și devine gata să se conecteze la clienți (această stare se numește deschis pasiv).

2. Clientul cere TCP să deschidă o conexiune la server la adresa IP și portul specificat (această stare se numește activ deschis).

3. Clientul TCP primește numărul secvenței inițiale (în acest exemplu - 1000) și trimite segment de sincronizare(segment de sincronizare - SYN). Acest segment poartă numărul secvenței, dimensiunea ferestrei de recepție (4K) și cel mai mare segment pe care clientul îl poate accepta (1460 octeți).

4. Când ajunge un SYN, serverul TCP primește A mea numărul secvenței de pornire (3000). Trimite un segment SYN care conține un număr de secvență de pornire (3000), ACK 1001 (ceea ce înseamnă că primul octet trimis de client este numerotat 1001), dimensiunea ferestrei de recepție (4K) și cel mai mare segment pe care îl poate primi serverul (1024 octeți) ).

5. Clientul TCP, după ce a primit mesajul SYN / ACK de la server, trimite ACK 3001 înapoi (primul octet al datelor trimise de server ar trebui să fie numerotat 3001).

6. Clientul TCP instruiește aplicația sa să deschidă o conexiune.

7. Serverul TCP, după ce a primit un mesaj ACK de la clientul TCP, își informează aplicația despre deschiderea conexiunii.

Clientul și serverul își anunță regulile pentru datele primite, își sincronizează numerele de ordine și devin gata să facă schimb de date. Specificația TCP permite, de asemenea, un alt scenariu (nu foarte reușit), când aplicațiile peer simultan se deschid reciproc.

10.4.2 Setarea valorilor parametrilor IP

Cererea de conexiune a aplicației poate specifica și parametrii pentru datagramele IP care vor transporta datele pentru acea conexiune. Dacă nu este specificată nicio valoare specifică a parametrului, se utilizează valoarea implicită.

De exemplu, o aplicație poate selecta valoarea dorită pentru prioritatea IP sau tipul de serviciu. Deoarece fiecare dintre părțile conectate își stabilește în mod independent propria prioritate și tipul de serviciu, teoretic, aceste valori pot diferi pentru diferite direcții ale fluxurilor de date. De regulă, în practică, aceleași valori sunt utilizate pentru fiecare direcție de schimb.

Atunci când o aplicație folosește opțiuni de securitate pentru agenții guvernamentale sau militare, fiecare dintre punctele finale ale conexiunii trebuie să utilizeze aceleași niveluri de securitate, altfel conexiunea nu va fi stabilită.

10.5 Transfer de date

Transferul de date începe după finalizarea confirmării în trei pași a creării conexiunii (vezi Fig. 10.9). Standardul TCP permite includerea datelor normale în segmente de confirmare, dar nu vor fi livrate aplicației până când conexiunea nu este completă. Pentru ușurința numerotării, sunt utilizate mesaje de 1000 de octeți. Fiecare segment de antet TCP are un câmp ACK care identifică numărul de secvență al octetului care se așteaptă să fie primit de la partenerul de pe conexiune..


Orez. 10.9. Flux de date simplu și ACK

Primul segment trimis de client conține octeți de la 1001 la 2000. Câmpul său ACK ar trebui să conțină o valoare de 3001, care indică numărul de secvență al octetului care se presupune a fi primit de la server.

Serverul răspunde clientului cu un segment care conține 1000 de octeți de date (începând de la 3001). Câmpul său de antet TCP ACK va indica faptul că octeții 1001 până în 2000 au fost deja primiți cu succes, deci următorul număr de secvență a segmentului așteptat ar trebui să fie 2001.

Clientul trimite apoi segmente începând cu octeți 2001, 3001 și 4001 în secvența specificată. Rețineți că clientul nu se așteaptă la un ACK după fiecare dintre segmentele trimise. Datele sunt trimise partenerului până când spațiul său tampon este plin (vom vedea mai jos că destinatarul poate indica foarte exact cantitatea de date trimise acestuia).

Serverul păstrează lățimea de bandă utilizând un singur ACK pentru a indica redirecționarea cu succes a tuturor segmentelor.

În fig. 10.10 arată transferul de date atunci când primul segment este pierdut. Când expiră expirarea, segmentul este retransmis. Rețineți că la primirea segmentului pierdut, receptorul trimite un ACK confirmând că ambele segmente au fost trimise.


Orez. 10.10. Pierderea și retransmiterea datelor

10.6 Închiderea unei conexiuni

Întreruperea normală a unei conexiuni se realizează utilizând aceeași procedură triplă de strângere de mână ca la deschiderea unei conexiuni. Fiecare dintre părți poate începe închiderea conexiunii în următorul scenariu:

A:

B:"Bun".

V:- Și eu am terminat treaba.

A:"Bun".

Următorul scenariu este, de asemenea, acceptabil (deși este rar utilizat):

A:"Am terminat. Nu mai sunt date de trimis."

V:"Bine. Cu toate acestea, există unele date ..."

V:- Și eu am terminat treaba.

A:"Bun".

În exemplul de mai jos, conexiunea închide serverul, așa cum se întâmplă adesea pentru comunicațiile client / server. În acest caz, după ce utilizatorul intră în sesiune telnet comenzi de deconectare serverul inițiază o cerere de închidere a conexiunii. În situația prezentată în Fig. 10.11, se efectuează următoarele acțiuni:

1. O aplicație de pe server îi spune TCP să închidă conexiunea.

2. Serverul TCP trimite un segment final (FIN) informându-i peer-ul său că nu mai există date de trimis.

3. TCP-ul clientului trimite un ACK pe segmentul FIN.

4. TCP-ul clientului spune aplicației sale că serverul dorește să închidă conexiunea.

5. Aplicația client spune TCP-ului său să închidă conexiunea.

6. TCP-ul clientului trimite un mesaj FIN.

7. Serverul TCP primește FIN de la client și răspunde cu un mesaj ACK.

8. Serverul TCP instruiește aplicația sa să închidă conexiunea.


Orez. 10.11.Închiderea unei conexiuni

Ambele părți pot începe să se închidă în același timp. În acest caz, închiderea normală a conexiunii este finalizată după ce fiecare partener trimite un mesaj ACK.

10.6.1 Încetarea bruscă

Fiecare dintre părți poate solicita o închidere bruscă a conexiunii. Acest lucru este acceptabil atunci când o aplicație dorește să încheie o conexiune sau când TCP întâmpină o problemă serioasă de comunicare pe care nu o poate rezolva singură. Încetarea bruscă este solicitată prin trimiterea unuia sau mai multor mesaje de resetare la egal, așa cum este indicat de un semnalizator specific în antetul TCP.

10.7 Controlul debitului

Receptorul TCP este încărcat cu fluxul de date primite și determină câte informații poate primi. Această limitare afectează expeditorul TCP. Explicația de mai jos pentru acest mecanism este conceptuală, iar dezvoltatorii îl pot implementa în moduri diferite în produsele lor.

În timpul configurării conexiunii, fiecare partener alocă spațiu pentru bufferul de intrare al conexiunii și notifică cealaltă parte a acestui lucru. De obicei, dimensiunea tamponului este exprimată ca un număr întreg de dimensiuni maxime ale segmentului.

Fluxul de date intră în bufferul de intrare și este stocat acolo înainte de a fi trimis aplicației (determinat de portul TCP). În fig. 10.12 arată un buffer de intrare capabil să accepte 4KB.


Orez. 10.12. Fereastra de recepție a bufferului de intrare

Spațiul tampon se umple odată cu sosirea datelor. Când aplicația primitoare preia date din buffer, spațiul eliberat devine disponibil pentru noile date primite.

10.7.1 Fereastra de primire

Fereastra de primire(fereastră de recepție) - orice spațiu din bufferul de intrare care nu este încă ocupat de date. Datele rămân în bufferul de intrare până când sunt consumate de aplicația țintă. De ce aplicația nu preia datele imediat?

Un scenariu simplu vă va ajuta să răspundeți la această întrebare. Să presupunem că un client a încărcat un fișier pe un server FTP care rulează pe un computer multi-utilizator foarte ocupat. Programul FTP trebuie să citească apoi datele din buffer și să le scrie pe disc. Când serverul efectuează operații de I / O pe disc, programul așteaptă finalizarea acelor operații. În acest moment, poate începe un alt program (de exemplu, conform unui program) și în timp ce programul FTP pornește din nou, următoarele date vor ajunge deja în buffer.

Fereastra de recepție se extinde de la ultimul octet recunoscut până la sfârșitul bufferului. În fig. 10.12 mai întâi, întregul buffer este disponibil și, prin urmare, este disponibilă o fereastră de recepție 4KB. Când ajunge primul KB, fereastra de recepție va fi redusă la 3 KB (pentru simplitate, vom presupune că fiecare segment are dimensiunea de 1 KB, deși în practică această valoare variază în funcție de nevoile aplicației). Sosirea următoarelor două segmente de 1 KB va reduce fereastra de recepție la 1 KB.

Fiecare ACK trimis de receptor conține informații despre starea curentă a ferestrei de recepție, în funcție de care este reglementat fluxul de date de la sursă.

În cea mai mare parte, dimensiunea bufferului de intrare este setată la momentul pornirii conexiunii, deși standardul TCP nu specifică modul de gestionare a acestui buffer. Tamponul de intrare poate crește sau micșora pentru a oferi feedback expeditorului.

Ce se întâmplă dacă un segment de intrare poate fi plasat în fereastra de recepție, dar nu a ajuns în ordine? În general, se presupune că toate implementările stochează datele primite în fereastra de recepție și trimit o confirmare (ACK) numai pentru un întreg bloc adiacent de mai multe segmente. Aceasta este metoda corectă, deoarece în caz contrar, aruncarea datelor în afara comenzii va degrada semnificativ performanța.

10.7.2 Fereastra de trimitere

Sistemul care transmite datele trebuie să țină evidența a două caracteristici: cât de multe date au fost deja trimise și confirmate și dimensiunea curentă a ferestrei de recepție a receptorului. Activ dispatch space(trimite spațiu) se extinde de la primul octet nerecunoscut la stânga ferestrei de recepție curente. Parte fereastră folosit de a trimite, indică cât de multe date suplimentare pot fi trimise partenerului.

Numărul secvenței inițiale și dimensiunea inițială a ferestrei de recepție sunt setate în timpul configurării conexiunii. Orez. 10.13 ilustrează unele dintre caracteristicile mecanismului de transfer de date.

1. Expeditorul începe cu o fereastră de trimitere 4KB.

2. Expeditorul trimite 1 KB. O copie a acestor date este păstrată până la primirea unei confirmări (ACK), deoarece poate fi necesară retransmiterea.

3. Sosește mesajul ACK pentru primul KB, iar următorii 2 KB de date sunt trimise. Rezultatul este prezentat în partea a treia din partea de sus a Fig. 10.13. Stocarea de 2 KB continuă.

4. În cele din urmă, ajunge un ACK pentru toate datele transmise (adică toate primite de receptor). ACK restabilește dimensiunea ferestrei de trimitere la 4K.

Orez. 10.13. Trimite fereastra

Ar trebui subliniate mai multe caracteristici interesante:

S Expeditorul nu așteaptă un ACK pentru fiecare dintre segmentele de date pe care le trimite. Singura limitare a transferului este dimensiunea ferestrei de recepție (de exemplu, expeditorul ar trebui să trimită doar segmente 4K de un singur octet).

S Să presupunem că expeditorul trimite date în mai multe segmente foarte scurte (de exemplu, 80 de octeți). În acest caz, datele pot fi reformatate pentru o transmisie mai eficientă (de exemplu, într-un singur segment).

10.8 Antet TCP

În fig. 10.14 arată formatul segmentului (antet TCP și date). Antetul începe cu ID-urile portului sursă și destinație. Următorul câmp următor număr de serie(numărul secvenței) indică poziția în fluxul de date de ieșire pe care îl ocupă acest segment. Camp ACK(confirmare) conține informații despre următorul segment preconizat care va apărea în fluxul de date de intrare.


Orez. 10.14. Segment TCP

Există șase steaguri:

Camp prejudecată de date(Offset de date) conține dimensiunea antetului TCP în cuvinte pe 32 de biți. Antetul TCP trebuie să se termine la o limită de 32 de biți.

10.8.1 Opțiune pentru dimensiunea maximă a segmentului

Parametru „dimensiunea maximă a segmentului”(dimensiunea maximă a segmentului - MSS) este utilizată pentru a face publicitate celei mai mari bucăți de date care pot fi primite și procesate de sistem. Cu toate acestea, titlul este oarecum inexact. De obicei în TCP segment tratate ca antet plus date. dar dimensiunea maximă a segmentului definit ca:

Cea mai mare datagramă pe care o puteți accepta este 40

Cu alte cuvinte, MSS reflectă cel mai mare încărcătură utilăîn receptor cu o lungime de anteturi TCP și IP de 20 de octeți. Dacă există parametri suplimentari, lungimea lor trebuie scăzută din dimensiunea totală. Prin urmare, cantitatea de date care poate fi trimisă într-un segment este definită ca:

Valoare declarată MSS + 40 - (suma lungimilor antetului TCP și IP)

De obicei, colegii schimbă valori MSS în mesajele SYN inițiale atunci când este deschisă o conexiune. Dacă sistemul nu promovează o dimensiune maximă a segmentului, se utilizează valoarea implicită de 536 octeți.

Dimensiunea segmentului maxim este codificată cu un preambul de 2 octeți urmat de o valoare de 2 octeți, adică cea mai mare valoare va fi 2 16 -1 (65.535 octeți).

MSS impune o limită dură pentru datele trimise către TCP: receptorul nu va putea procesa valori mari. Cu toate acestea, expeditorul utilizează segmente mai mica, deoarece MTU de-a lungul căii este determinat și pentru conexiune.

10.8.2 Utilizarea câmpurilor de antet într-o cerere de conectare

Primul segment trimis pentru a deschide o conexiune are un flag SYN de 1 și un flag ACK de 0. SYN inițial este singurul un segment care are un câmp ACK de 0. Rețineți că securitatea folosește această caracteristică pentru a detecta cererile primite pentru o sesiune TCP.

Camp număr de serie conține numărul secvenței inițiale(numărul secvenței inițiale), câmp fereastră - dimensiunea inițială fereastra de primire. Singurul parametru TCP definit în prezent este dimensiunea maximă a segmentului (când nu este specificat, valoarea implicită este de 536 octeți) pe care TCP se așteaptă să o primească. Această valoare are o lungime de 32 de biți și este de obicei prezentă în cererea de conectare în câmp Opțiuni(Opțiune). Antetul TCP care conține valoarea MSS are o lungime de 24 de octeți.

10.8.3 Utilizarea câmpurilor de antet în răspunsul conexiunii

Într-un răspuns de activare la o cerere de conectare, ambele semnalizatoare (SYN și ACK) sunt egale cu 1. Sistemul care răspunde indică numărul secvenței inițiale în câmpul corespunzător și dimensiunea ferestrei de recepție în câmp Fereastră... Dimensiunea maximă a segmentului pe care destinatarul dorește să o utilizeze se găsește de obicei în răspunsul la solicitarea de conectare (în Opțiuni). Această valoare poate fi diferită de valoarea părții care solicită conexiunea, adică pot fi utilizate două valori diferite.

O cerere de conexiune poate fi respinsă prin specificarea unui flag de resetare (RST) cu o valoare de 1 în răspuns.

10.8.4 Selectarea numărului secvenței de pornire

Specificația TCP presupune că în timpul stabilirii conexiunii, fiecare parte alege numărul secvenței inițiale(la valoarea curentă a temporizatorului intern pe 32 de biți). Cum se face asta?

Imaginați-vă ce se întâmplă atunci când sistemul se blochează. Să presupunem că utilizatorul a deschis o conexiune chiar înainte de blocare și a trimis o cantitate mică de date. După recuperare, sistemul nu-și mai amintește nimic din ceea ce a fost făcut înainte de blocare, inclusiv conexiuni care rulează deja și numere de port atribuite. Utilizatorul restabilește conexiunea. Numerele de port nu se potrivesc cu atribuțiile inițiale, iar unele dintre ele ar putea fi deja utilizate de alte conexiuni stabilite cu câteva secunde înainte de blocare.

Prin urmare, cealaltă parte de la capătul conexiunii poate să nu știe că partenerul său a trecut printr-un colaps și munca sa a fost apoi restaurată. Toate acestea vor duce la întreruperi grave, mai ales când este nevoie de mult timp pentru ca datele vechi să călătorească prin rețea și să se amestece cu datele de la conexiunea nou creată. Selectarea temporizatorului pentru noul start elimină astfel de probleme. Datele vechi vor avea o numerotare diferită de gama de numere de ordine a noii conexiuni. Hackerii, atunci când falsifică adresa IP sursă pentru o gazdă de încredere, încearcă să obțină acces la computere specificând un număr de secvență de pornire previzibil în mesaj. O funcție hash criptografică bazată pe chei interne este cel mai bun mod de a selecta numerele de semințe sigure.

10.8.5 Utilizarea obișnuită a câmpurilor

La pregătirea antetului TCP pentru transmisie, numărul de secvență al primului octet al datelor transmise este indicat în câmp număr secvențial(Număr de secvență).

Următorul număr de octet așteptat de la partenerul de conexiune este introdus în câmp confirmare(Număr de confirmare) când bitul ACK este setat la 1. Câmp fereastră(Window) este pentru dimensiunea curentă a ferestrei de recepție. Acest câmp conține numărul de octeți din numărul de confirmare care poate fi acceptat... Rețineți că această valoare permite controlul precis al fluxului de date. Folosind această valoare, partenerul indică starea reală a ferestrei de recepție în timpul sesiunii de schimb.

Dacă aplicația indică o operațiune push TCP, atunci semnalizatorul PUSH este setat la 1. TCP-ul destinatar TREBUIE să răspundă la acest semnal livrând rapid date aplicației imediat ce expeditorul dorește să le trimită.

Steagul URGENT, dacă este setat la 1, implică transfer de date urgent, iar indicatorul corespunzător TREBUIE să se refere la ultimul octet de date urgente. O utilizare tipică pentru date urgente este de a trimite semnale de anulare sau de întrerupere de la terminal.

Se apelează adesea la date urgente informații în afara benzii(în afara benzii). Cu toate acestea, acest termen este inexact. Datele accelerate sunt trimise pe un flux TCP obișnuit, deși unele implementări pot avea mecanisme speciale pentru a indica aplicației că au sosit date urgente, iar aplicația trebuie să verifice conținutul datelor urgente înainte ca toți octeții mesajului să sosească.

Semnalizatorul RESET este setat la 1 pentru a întrerupe conexiunea. Același semnal este setat în răspuns la sosirea unui segment care nu este asociat cu niciuna dintre conexiunile TCP curente.

FIN este setat la 1 pentru mesajele de închidere a conexiunii.


10.8.6 Suma de control

Suma de control IP este doar pentru antetul IP, iar suma de control TCP este calculată pentru întregul segment, precum și pseudo-antetul generat din antetul IP. În timpul calculului sumei de control TCP, câmpul corespunzător este setat la 0. În fig. 10.15 prezintă un pseudo-antet foarte similar cu cel utilizat în suma de verificare UDP.


Orez. 10.15. Câmpul pseudo-antet este inclus în suma de control TCP

Lungimea TCP este calculată prin adăugarea lungimii antetului TCP cu lungimea datelor. Suma de control TCP este obligatoriu, nu ca UDP. Suma de control a segmentului primit este calculată mai întâi de către receptor și apoi comparată cu conținutul câmpului de sumă de control al antetului TCP. Dacă valorile nu se potrivesc, segmentul este eliminat.

10.9 Exemplu de segment TCP

Orez. 10.16, protocol de funcționare a analizorului Sniffer de Network General, este o secvență de segmente TCP. Primele trei segmente stabilesc o conexiune între client și server Telnet... Ultimul segment transportă 12 octeți de date.


Orez. 10.16. Afișarea antetului TCP de către Sniffer Analyzer

Analizor Sniffer traduce majoritatea valorilor în zecimal. Cu toate acestea, valorile semnalizatorului sunt redate ca hexazecimale. Semnalizatorul cu valoarea 12 este 010010. Suma de control este afișată și în hexazecimal.

10.10 Suport pentru sesiune

10.10.1 Testarea ferestrei

Un expeditor rapid și un receptor lent pot forma o fereastră de recepție de 0 octeți. Acest rezultat se numește închizând fereastra(fereastră închisă). Când există spațiu liber pentru actualizarea dimensiunii ferestrei de recepție, se folosește ACK. Cu toate acestea, dacă un astfel de mesaj se pierde, ambele părți vor trebui să aștepte la nesfârșit.

Pentru a evita această situație, expeditorul setează temporizator stocat(cronometru persistent) când fereastra este închisă. Valoarea temporizatorului ia timpul de retransmisie. La sfârșitul cronometrului, un segment este trimis partenerului fereastră sonoră(fereastra sondă; unele implementări includ și date). Sondajul îl determină peer să trimită înapoi un ACK care raportează starea curentă a ferestrei.

Dacă fereastra are încă dimensiunea zero, valoarea temporizatorului stocat este dublată. Acest proces se repetă până când cronometrul atinge maximum 60 de secunde. TCP va continua să trimită mesaje de sondare la fiecare 60 de secunde - până la deschiderea ferestrei, până când utilizatorul finalizează procesul sau până la expirarea aplicației.

10.11 Deconectare

10.11.1 Timeout

Partenerul de conexiune se poate bloca sau poate fi întrerupt complet din cauza unui gateway sau a unei eșecuri de comunicare. Există mai multe mecanisme pentru a împiedica TCP să trimită din nou date.

La atingerea primului prag pentru retransmisie (retransmisie), TCP îi spune IP-ului să verifice routerul eșuat și în același timp informează aplicația despre problemă. TCP continuă să trimită date până la atingerea celei de-a doua valori limită și abia apoi termină conexiunea.

Desigur, înainte ca acest lucru să se întâmple, poate sosi un mesaj ICMP care să ateste că destinația este inaccesibilă din anumite motive. În unele implementări, chiar și atunci, TCP va continua să încerce să acceseze destinația până la expirarea intervalului de expirare (după care problema poate fi rezolvată). Apoi, aplicația este informată că destinația este inaccesibilă.

Aplicația își poate seta propriul timeout de livrare a datelor și poate efectua propriile operațiuni la sfârșitul acestui interval. Conexiunea este de obicei deconectată.

10.11.2 Menținerea conexiunii

Când o conexiune incompletă are date de transferat pentru o lungă perioadă de timp, aceasta devine starea inactivă. În timpul unei perioade de inactivitate, poate apărea o blocare a rețelei sau pierderea legăturilor fizice. De îndată ce rețeaua devine din nou operațională, partenerii vor continua să facă schimb de date fără a întrerupe sesiunea de comunicare. Această strategie a fost în conformitate cu cerințele Ministerului Apărării.

Cu toate acestea, orice conexiune - activă sau inactivă - ocupă multă memorie de calculator. Unii administratori trebuie să returneze resursele neutilizate către sisteme. Prin urmare, multe implementări TCP pot trimite un mesaj despre păstrarea conexiunii(păstrați în viață) testarea conexiunilor inactive. Astfel de mesaje sunt trimise periodic partenerului pentru a verifica existența acestuia în rețea. Mesajele ACK trebuie primite ca răspuns. Utilizarea mesajelor keepalive este opțională. Dacă sistemul are această capacitate, aplicația o poate anula prin mijloace proprii. Perioada estimată Mod implicit timpul limită pentru menținerea unei conexiuni este de două ore!

Amintiți-vă că aplicația își poate seta propriul temporizator, conform căruia, la propriul nivel, va lua o decizie cu privire la sfârșitul conexiunii.

10.12 Performanţă

Cât de eficient este TCP? Mulți factori afectează performanța resurselor, dintre care memoria și lățimea de bandă sunt principalii (a se vedea Figura 10.17).


Orez. 10.17. Factori de performanță TCP

Lățimea de bandă și latența în rețeaua fizică utilizată vor limita sever lățimea de bandă. Calitatea slabă a transferului de date are ca rezultat un volum mare de datagrame scăzute, ceea ce determină retransmisia și, ca rezultat, reduce eficiența lățimii de bandă.

Partea destinatară trebuie să ofere suficient spațiu tampon pentru a permite expeditorului să transfere date fără întrerupere. Acest lucru este deosebit de important pentru rețelele cu latență ridicată, unde există un interval lung de timp între trimiterea datelor și primirea unui ACK (și, de asemenea, atunci când se negociază dimensiunea ferestrei). Pentru a menține un flux stabil de date de la sursă, partea de recepție trebuie să aibă o fereastră de cel puțin lățimea de bandă de ori de întârziere a produsului.

De exemplu, dacă sursa poate trimite date la o rată de 10.000 de octeți / s și durează 2 secunde pentru a returna un ACK, atunci pe cealaltă parte trebuie să oferiți o fereastră de recepție de cel puțin 20.000 de octeți, altfel fluxul de date nu va fi continuu. Un tampon de recepție de 10.000 de octeți va reduce debitul la jumătate.

Un alt factor important pentru performanță este capacitatea gazdei de a răspunde la evenimente cu prioritate ridicată și de a executa rapid comutarea contextului, adică finalizați unele operații și treceți la altele. Gazda poate sprijini interactiv mulți utilizatori locali, procese de fundal de loturi și zeci de conexiuni de comunicare simultane. Comutarea contextuală permite întreținerea tuturor acestor operațiuni în timp ce ascundeți sarcina pe sistem. Implementările care integrează TCP / IP cu nucleul sistemului de operare pot reduce semnificativ încărcătura din utilizarea comutării de context.

Resursele unității centrale de procesare a computerului sunt necesare pentru procesarea antetelor TCP. Dacă procesorul nu poate calcula rapid sumele de control, va încetini rata de transfer a datelor prin rețea.

În plus, dezvoltatorii ar trebui să ia în considerare facilitarea configurării setărilor TCP, astfel încât administratorul de rețea să le poată personaliza pentru a se potrivi cerințelor lor locale. De exemplu, capacitatea de a regla dimensiunea bufferului pentru lățimea de bandă și latența rețelei va îmbunătăți dramatic performanța. Din păcate, multe implementări nu acordă suficientă atenție acestei probleme și codifică cu greu parametrii de comunicare.

Să presupunem că mediul de rețea este perfect: există resurse suficiente și comutarea contextului este mai rapidă decât cowboy-urile care își scot revolverii. Veți obține performanțe excelente?

Nu intotdeauna. Contează și calitatea dezvoltării software-ului TCP. Multe probleme de performanță au fost diagnosticate și rezolvate de-a lungul anilor în diferite implementări TCP. Cel mai bun software este RFC 1122, care definește cerințele de nivel de comunicare pentru gazdele de Internet.

La fel de importantă este și excepția și aplicarea algoritmilor Jacobson, Kern și Partridge (acești algoritmi interesanți vor fi discutați mai jos).

Dezvoltatorii de software pot obține beneficii semnificative prin crearea de programe care elimină transferurile inutile de cantități mici de date și au temporizatoare încorporate pentru resurse gratuite de rețea care nu sunt utilizate în prezent.

10.13 Algoritmi de îmbunătățire a performanței

Trecând la partea destul de complexă a TCP, vom analiza mecanismele de îmbunătățire a performanței și rezolvarea blocajelor lățimii de bandă. Această secțiune discută următoarele probleme:

Start lent(pornire lentă) împiedică utilizarea unei proporții mari din traficul de rețea pentru o nouă sesiune, ceea ce poate duce la suprasolicitare.

■ Recuperare din sindromul ferestrei goofy(sindromul ferestrei stupide) previne suprasolicitarea rețelei de mesaje a aplicațiilor slab concepute.

ACK întârziat(ACK întârziat) reduce congestia prin reducerea numărului de mesaje independente de confirmare directă.

Timp limită de retransmisie calculat(calculul timpului de retransmisie) se bazează pe negocierea în timp real a sesiunii, reducând retransmisiunile inutile, dar fără a provoca întârzieri mari pentru schimburile de date cu adevărat necesare.

■ Încetiniți redirecționarea TCP când supraîncărcăriîn rețea permite routerelor să revină la modul lor original și să partajeze resursele de rețea pentru toate sesiunile.

■ Trimiterea ACK duplicate(ACK duplicat) când primiți un segment în afara secvenței, permite colegilor să trimită din nou înainte de expirarea timpului.

10.13.1 Pornire lentă

Dacă toate aparatele de uz casnic sunt pornite în același timp acasă, va apărea o supraîncărcare a rețelei electrice. În rețelele de calculatoare start lent previne suflarea siguranțelor de la rețea.

O nouă conexiune care declanșează instantaneu transferul unor cantități mari de date într-o rețea deja încărcată poate duce la probleme. Ideea din spatele pornirii lente este de a vă asigura că noua conexiune are un pornire reușită în timp ce crește încet rata de transfer de date în funcție de încărcarea reală a rețelei. Expeditorul este limitat de dimensiunea ferestrei de încărcare, nu de fereastra mare de recepție.

Fereastra de încărcare(fereastra de congestie) începe cu o dimensiune de 1 segment. Pentru fiecare segment cu un ACK primit cu succes, fereastra de încărcare este mărită cu 1 segment atâta timp cât rămâne mai mică decât fereastra de recepție. Dacă rețeaua nu este supraîncărcată, fereastra de încărcare va ajunge treptat la dimensiunea ferestrei de recepție. În condiții normale de redirecționare, aceste ferestre vor avea aceeași dimensiune.

Rețineți că pornirea lentă nu este atât de lentă. După primul ACK, dimensiunea ferestrei de încărcare este egală cu 2 segmente, iar după ce ați primit cu succes un ACK pentru două segmente, dimensiunea poate crește la 8 segmente. Cu alte cuvinte, dimensiunea ferestrei crește exponențial.

Să presupunem că, în loc să primiți un ACK, a apărut o situație de expirare. Comportamentul ferestrei de încărcare în acest caz este discutat mai jos.

10.13.2 Sindromul ferestrei clueless

În primele implementări ale TCP / IP, dezvoltatorii s-au confruntat cu fenomenul sindromul ferestrei goofy(Silly Window Syndrome - SWS), care a apărut destul de des. Pentru a înțelege evenimentele care au loc, luați în considerare următorul scenariu, care duce la consecințe nedorite, dar este foarte posibil:

1. Aplicația de trimitere trimite date rapid.

2. Aplicația primitoare citește 1 octet de date din bufferul de intrare (adică încet).

3. Bufferul de intrare se umple rapid după citire.

4. Aplicația primitoare citește 1 octet și TCP trimite un ACK care înseamnă „Am spațiu liber pentru 1 octet de date”.

5. Aplicația de trimitere trimite un pachet TCP de 1 octet prin rețea.

6. TCP-ul care primește trimite un ACK care înseamnă „Mulțumesc. Am primit un pachet și nu mai am spațiu liber”.

7. Aplicația primitoare citește din nou 1 octet și trimite un ACK, iar întregul proces se repetă.

O aplicație cu recepție lentă așteaptă mult timp să sosească datele și împinge constant informațiile primite către marginea stângă a ferestrei, efectuând o operațiune complet inutilă, care generează trafic suplimentar în rețea.

Situațiile din viața reală, desigur, nu sunt atât de extreme. Un expeditor rapid și un receptor lent vor schimba mici bucăți de date (în raport cu dimensiunea maximă a segmentului) și vor comuta într-o fereastră de recepție aproape completă. În fig. 10.18 arată condițiile pentru apariția sindromului „fereastra goofă”.


Orez. 10.18. Primiți tampon pentru ferestre cu spațiu liber foarte mic

Această problemă nu este greu de rezolvat. De îndată ce fereastra de recepție se micșorează mai puțin decât dimensiunea țintă dată, TCP începe să păcălească expeditorul. În această situație, TCP nu ar trebui să îndrepte către expeditor adiţional spațiu în fereastră atunci când aplicația primitoare citește date din buffer în bucăți mici. În schimb, resursele eliberate ar trebui să fie păstrate secrete de la expeditor până când sunt suficiente. Dimensiunea recomandată este un segment, cu excepția cazului în care întregul buffer de intrare conține un singur segment (în acest din urmă caz, se folosește o dimensiune egală cu jumătate din buffer). Dimensiunea țintă care trebuie raportată de TCP poate fi exprimată ca:

minim (1/2 buffer de intrare, dimensiune maximă a segmentului)

TCP începe să trișeze atunci când dimensiunea ferestrei devine mai mică decât această dimensiune și va spune adevărul atunci când dimensiunea ferestrei nu este mai mică decât valoarea obținută de formulă. Rețineți că nu există nici un prejudiciu pentru expeditor, deoarece aplicația primitoare nu ar putea totuși să proceseze majoritatea datelor pe care le așteaptă.

Soluția propusă poate fi ușor verificată în cazul de mai sus cu o ieșire ACK pentru fiecare dintre octeții primiți. Aceeași metodă este potrivită și pentru cazul în care tamponul de intrare poate stoca mai multe segmente (așa cum se întâmplă adesea în practică). Expeditorul rapid va umple bufferul de intrare, dar receptorul va indica faptul că nu are spațiu liber pentru stocarea informațiilor și nu va deschide această resursă până când dimensiunea sa nu ajunge la întregul segment.

10.13.3 Algoritmul lui Nagle

Expeditorul ar trebui, indiferent de destinatar, să excludă transmiterea unor segmente foarte scurte, acumulând date înainte de trimitere. Algoritmul Nagle implementează o idee foarte simplă pentru a reduce numărul datagramelor scurte trimise prin rețea.

Algoritmul recomandă întârzierea transferului de date (și împingerea) prin așteptarea ACK din datele transmise anterior. Datele acumulate sunt trimise după primirea unui ACK pe o informație trimisă anterior sau după primirea datelor pentru trimiterea în mărimea unui segment complet sau după expirarea expirării. Acest algoritm nu trebuie utilizat pentru aplicații în timp real care trebuie să trimită date cât mai repede posibil.

10.13.4 ACK întârziat

Un alt mecanism de îmbunătățire a performanței este metoda de întârziere ACK. Reducerea numărului de ACK-uri reduce cantitatea de lățime de bandă care poate fi utilizată pentru redirecționarea altor traficuri. Dacă partenerul TCP întârzie ușor trimiterea ACK, atunci:

■ Puteți confirma recepția mai multor segmente cu un singur ACK.

■ Aplicația destinatară poate primi o cantitate de date în intervalul de expirare; antetul de ieșire poate fi inclus în ACK și nu necesită formarea unui mesaj separat.

Pentru a evita întârzierile la trimiterea unui flux de segmente de dimensiuni complete (de exemplu, la schimbul de fișiere), un ACK trebuie trimis cel puțin pentru fiecare al doilea segment complet.

Multe implementări utilizează 200 ms timeout. Dar întârzierea ACK nu încetinește cursul de schimb. Când ajunge un segment scurt, există încă suficient spațiu liber în bufferul de intrare pentru a primi date noi, iar expeditorul poate continua să trimită (în plus, retransmisia este de obicei mult mai lentă). Dacă ajunge un segment întreg, trebuie să răspundeți la acesta cu un mesaj ACK în aceeași secundă.

10.13.5 Timp expirare retransmisie

După trimiterea segmentului, TCP setează un cronometru și monitorizează sosirea ACK. Dacă nu se primește ACK în perioada de expirare, TCP retransmite segmentul (releu). Cu toate acestea, care ar trebui să fie perioada de expirare?

Dacă este prea scurt, expeditorul va umple rețeaua cu redirecționarea segmentelor inutile care duplică informațiile deja trimise. Un timp prea lung vă va împiedica să reparați rapid segmente care sunt foarte rele în timpul transferului, ceea ce va reduce debitul.

Cum se alege intervalul de expirare corect? O valoare bună pentru o rețea LAN de mare viteză nu este bună pentru o conexiune la distanță cu mai multe accesări. Aceasta înseamnă că principiul „unei valori pentru toate condițiile” este în mod clar inadecvat. Mai mult, chiar și pentru o conexiune specifică existentă, condițiile de rețea se pot schimba, iar întârzierile pot crește sau scădea.

Algoritmii Jacobson, Kern și Partridge (descriși în articole , Van Jacobson și Îmbunătățirea estimărilor de timp dus-întors în protocoale de transport fiabile, Karn și Partridge) permit TCP să se adapteze la condițiile de rețea în schimbare. Acești algoritmi sunt recomandați pentru utilizare în implementări noi. Le vom acoperi pe scurt mai jos.

Simțul comun dictează faptul că cea mai bună bază pentru estimarea timpului de expirare corect pentru o anumită conexiune poate fi durata ciclului(timpul dus-întors) ca interval între trimiterea datelor și primirea confirmării primirii lor.

Deciziile bune pentru următoarele cantități pot fi obținute din statistici de bază (a se vedea Figura 10.19) care vă pot ajuta să calculați timpul de expirare. Cu toate acestea, nu este nevoie să vă bazați pe medii, deoarece mai mult de jumătate din estimări vor fi mai mari decât media. Privind câteva abateri, puteți obține estimări mai corecte, luând în considerare distribuția normală și reducând timpul de așteptare prea lung al retransmisiei.


Orez. 10.19. Distribuirea timpilor ciclului

Nu este nevoie de o cantitate mare de calcul pentru a obține estimări matematice formale ale abaterilor. Estimările aproximative pot fi utilizate pe baza valorii absolute a diferenței dintre ultima valoare și media estimată:

Ultima abatere = | Ultimul ciclu - Mediu |

Un alt factor de luat în considerare atunci când se calculează expirarea corectă este modificarea timpului ciclului din cauza condițiilor curente ale rețelei. Ce s-a întâmplat pe web în ultimul moment este mai important decât ceea ce s-a întâmplat acum o oră.

Să presupunem că calculați o medie a ciclului pentru o sesiune foarte lungă. Chiar dacă rețeaua a fost inițial încărcată ușor și am determinat 1000 de valori mici, atunci a existat o creștere a traficului, cu o creștere semnificativă a latenței.

De exemplu, dacă 1000 de valori au dat o medie de 170 de unități, dar apoi 50 de valori au fost măsurate cu o medie de 282, atunci media curentă va fi:

170 × 1000/1050 + 282 × 50/1050 = 175

Mai rezonabilă ar fi valoarea timpul de ciclu netezit(Smoothed Round-Trip Time - SRTT), care ia în considerare prioritatea valorilor ulterioare:

SRTT nou = (1 - α) × (SRTT vechi) + α × Valoarea ultimului ciclu

Valoarea α este între 0 și 1. Măriți un rezultă o influență mai mare a timpului curent al ciclului asupra mediei netezite. Deoarece calculatoarele se pot împărți rapid la puteri de 2 prin deplasarea numerelor binare la dreapta, α este întotdeauna ales să fie (1/2) n (de obicei 1/8), deci:

SRTT nou = 7/8 × SRTT vechi + 1/8 × Timpul ultimului ciclu

Tabelul 10.2 arată modul în care formula pentru SRTT se ajustează la valoarea SRTT curentă de 230 atunci când o modificare a stării rețelei duce la o creștere progresivă a timpului ciclului (presupunând că nu are loc niciun timeout). Valorile din coloana 3 sunt utilizate ca valori din coloana 1 pentru următorul rând din tabel (adică ca vechiul SRTT).


Tabelul 10.2 Calculul duratei ciclului netezit

Vechiul SRTT Cel mai recent RTT (7/8) × (SRTT vechi) + (1/8) × (RTT)
230.00 294 238.00
238.00 264 241.25
241.25 340 253.59
253.59 246 252.64
252.64 201 246.19
246.19 340 257.92
257.92 272 259.68
259.68 311 266.10
266.10 282 268.09
268.09 246 265.33
265.33 304 270.16
270.16 308 274.89
274.89 230 269.28
269.28 328 276.62
276.62 266 275.29
275.29 257 273.00
273.00 305 277.00

Acum există o întrebare cu privire la alegerea unei valori pentru expirarea timpului de retransmisie. Analiza timpilor ciclului arată o abatere semnificativă a acestor valori față de media curentă. Este logic să stabiliți o limită pentru magnitudinea abaterilor (abateri). Valori bune pentru expirarea timpului de retransmisie (numit Retransmission TimeOut - RTO în standardele RFC) sunt date de următoarea formulă cu o constrângere de deviere netezită (SDEV):

T = Expirare retransmisie = SRTT + 2 × SDEV

T = SRTT + 4 × SDEV

Pentru a calcula SDEV, se determină mai întâi valoarea absolută a abaterii curente:

DEV = | Timpul ultimului ciclu - SRTT vechi |

Formula de netezire este apoi utilizată pentru a ține cont de ultima valoare:

SDEV nou = 3/4 × SDEV vechi + 1/4 × DEV

Rămâne o întrebare - care sunt valorile inițiale? Recomandat:

Timeout inițial = 3 s

SRTT inițială = 0

SDEV inițial = 1,5 s

Van Jacobson a definit un algoritm rapid care calculează timpul de retransmisie foarte eficient.

10.13.6 Exemple de statistici

Cât de bine va funcționa expirarea calculată mai sus? Când s-a realizat această valoare, s-au observat îmbunătățiri semnificative ale performanței. Un exemplu ar fi statisticile echipei netstat primite pe sistem tigger- un server de internet accesat de multe gazde din întreaga lume.


1510769 pachete (314955304 octeți) primite în ordine

Sistem tigger mai puțin de 2,5% din segmentele de date TCP au fost retransmise. Pentru un milion și jumătate de segmente de date primite (restul sunt mesaje ACK pure), doar 0,6% a fost duplicat. Trebuie avut în vedere faptul că nivelul pierderii din datele de intrare corespunde aproximativ nivelului pentru segmentele de ieșire. Astfel, traficul de retransmisie inutil reprezintă aproximativ 0,6% din totalul traficului.

10.13.7 Calcule după reluare

Formulele de mai sus utilizează valoarea timpului ciclului ca interval între trimiterea unui segment și primirea unei confirmări. Totuși, să presupunem că nu se recepționează nicio confirmare în timpul perioadei de expirare și că datele trebuie trimise din nou.

Algoritmul lui Kern presupune că timpul ciclului nu ar trebui schimbat în acest caz. Valoarea curentă a duratei ciclului și abaterea netezită păstrați-le valorile până când este primită o confirmare pentru a trimite un anumit segment fără a o retrimite. În acest moment, calculele sunt reluate pe baza valorilor stocate și a noilor măsurători.

10.13.8 Acțiuni după retransmisie

Dar ce se întâmplă înainte de primirea confirmării? După retransmisie, comportamentul TCP se schimbă radical, în principal din cauza pierderii datelor din congestia rețelei. Prin urmare, răspunsul la re-trimiterea datelor va fi:

■ Reducerea vitezei de reexpediere

■ Reduceți congestia rețelei prin reducerea traficului general

10.13.9 Frânare exponențială

După retransmisie, intervalul de expirare este dublat. Totuși, ce se întâmplă dacă temporizatorul se revarsă din nou? Datele vor fi trimise din nou, iar perioada de retransmisie se va dubla din nou. Acest proces se numește decelerare exponențială(retrogradare exponențială).

Dacă eșecul de rețea persistă, perioada de expirare se va dubla până când se atinge valoarea maximă presetată (de obicei 1 minut). Doar un segment poate fi trimis după expirare. Expirarea are loc, de asemenea, atunci când valoarea presetată pentru numărul de transferuri de date fără a primi un ACK este depășită.

10.13.10 Reducerea congestiei prin reducerea cantității de date trimise prin rețea

Reducerea cantității de date trimise este oarecum mai complexă decât mecanismele discutate mai sus. Începe să funcționeze, ca și pornirea lentă deja menționată. Dar, întrucât este stabilită o limită pentru nivelul de trafic, care poate duce inițial la probleme, cursul de schimb va încetini efectiv din cauza unei creșteri a dimensiunii ferestrei de încărcare pentru un segment. Trebuie să setați valori de margine pentru a reduce cu adevărat viteza de încărcare. În primul rând, se calculează pragul de pericol:

Limită - 1/2 minim (fereastra de încărcare curentă, fereastra de primire a partenerului)

Dacă valoarea obținută este mai mare de două segmente, aceasta este utilizată ca graniță. În caz contrar, marginea este setată la două segmente. Un algoritm complet de recuperare necesită:

■ Setați dimensiunea ferestrei de încărcare la un segment.

■ Pentru fiecare ACK primit, creșteți fereastra de încărcare cu un segment până când limita este atinsă (la fel ca un mecanism de pornire lentă).

■ Apoi, cu fiecare ACK primit, adăugați o valoare mai mică ferestrei de încărcare, care este selectată pe baza ratei de creștere pe un segment pentru timpul ciclului (creșterea este calculată ca MSS / N, unde N este dimensiunea fereastra de încărcare în segmente).

Un scenariu ideal ar putea simplifica activitatea mecanismului de recuperare. Să presupunem că fereastra de primire a partenerului (și fereastra de încărcare curentă) avea o dimensiune de 8 segmente înainte de a fi detectată expirarea, iar limita a fost definită ca 4 segmente. Dacă aplicația primitoare citește instantaneu date din buffer, fereastra de recepție va rămâne la 8 segmente.

■ Se trimite 1 segment (fereastră de încărcare = 1 segment).

■ ACK Received - sunt trimise 2 segmente.

■ ACK pentru 2 segmente primite - se trimit 4 segmente, (limita a fost atinsă).

■ ACK primit pentru 4 segmente. Se trimit 5 segmente.

■ ACK primit pentru 5 segmente. Se trimit 6 segmente.

■ ACK primit pentru 6 segmente. Sunt trimise 7 segmente.

■ ACK primit pentru 7 segmente. Sunt trimise 8 segmente (fereastra de încărcare este din nou egală ca dimensiune cu fereastra de recepție).

Deoarece este necesară confirmarea tuturor datelor trimise în timpul expirării retransmisiei, procesul continuă până când fereastra de încărcare atinge dimensiunea ferestrei de recepție. Evenimentele care au loc sunt prezentate în Fig. 10.20. Dimensiunea ferestrei crește exponențial, dublându-se în timpul perioadei de pornire lentă și, la atingerea limitei, crește liniar.


Orez. 10.20. Limitarea ratei de transfer în timpul congestiei

10.13.11 ACK-uri duplicate

În unele implementări, se folosește o caracteristică opțională - așa-numitul reexpediere rapidă(retransmisie rapidă) - pentru a accelera retransmiterea datelor în anumite condiții. Ideea sa principală este legată de trimiterea de ACK-uri suplimentare de către receptor, indicând o lacună în datele primite.

Primind un segment ieșit din ordine, receptorul trimite înapoi un ACK care indică primul octet pierdut date (vezi Figura 10.21).


Orez. 10.21. ACK duplicate

Expeditorul nu retransmite instantaneu datele, deoarece IP poate livra în mod normal date către destinatar fără o secvență de trimitere. Dar când sunt primite mai multe ACK-uri suplimentare pentru date duplicate (de exemplu, trei), atunci segmentul lipsă va fi trimis fără a aștepta expirarea expirării.

Rețineți că fiecare ACK duplicat indică primirea unui segment de date. Câteva ACK-uri duplicate vă anunță că rețeaua este capabilă să furnizeze suficiente date și, prin urmare, nu este supraîncărcată. Ca parte a algoritmului general, se realizează o mică reducere a dimensiunii ferestrei de încărcare, cu o creștere reală a traficului de rețea. În acest caz, procesul de redimensionare radicală la restabilirea muncii nu se aplică.

Conform standardului Cerințe de gazdă(cerințe gazdă) TCP trebuie să facă același pornire lentă descrisă mai sus atunci când se stinge sursa (stingerea sursei). Cu toate acestea, raportarea nu este direcționată sau eficientă, deoarece conexiunea care primește acest mesaj poate să nu genereze prea mult trafic. Specificație curentă Cerințele routerului(cerințele routerului) indică faptul că routerele nu ar trebui trimite mesaje despre suprimarea sursei.

10.13.13 Statistici TCP

În cele din urmă, să aruncăm o privire asupra mesajelor statistice ale comenzii netstat, pentru a vedea la lucru multe dintre mecanismele descrise mai sus.

Segmentele sunt denumite pachete.
879137 pachete de date (226966295 octeți)
21815 pachete de date (8100927 octeți) retransmise
Retrimiterea.
132957 pachete numai ack (104216 întârziat)
Remarcăm un număr mare de

ACK întârziat.

Sondarea deschiderii ferestrei

dimensiune zero.

Acestea sunt mesaje SYN și FIN.
762469 acks (pentru 226904227 octeți)
Alertă pentru sosirea coletelor

în afara secvenței.

1510769 pachete (314955304 octeți)
9006 pachete complet duplicate (867042 octeți)
Rezultatul timeout-ului când este real

livrarea datelor.

74 de pachete cu unele dup. date (12193 bytes duped)
Pentru o eficiență mai mare

unele dintre date au fost reambalate pentru a include octeți suplimentari când au fost retrimise.

13452 pachete scoase din comandă (2515087 octeți)
530 pachete (8551 octeți) de date după fereastră
Poate că aceste date au fost

incluse în mesajele de detectare.

402 pachete primite după închidere
Acestea sunt reluări ulterioare

trimiterea.

108 aruncate pentru sumele de control defecte
Suma de control TCP nevalidă.
0 aruncat pentru câmpuri de compensare antet greșite
7 aruncat deoarece pachetul este prea scurt
14677 conexiuni stabilite (inclusiv acceptări)
18929 conexiuni închise (inclusiv 643 picături)
4100 de conexiuni embrionare au scăzut
572187 segmente rtt actualizate (din 587397 încercări)
Încercări de schimbare nereușite

timpul ciclului, deoarece ACK nu a avut timp să sosească înainte de expirarea expirării,

26 de conexiuni au renunțat la expirarea timpului de înregistrare
Încercări ulterioare nereușite

retrimiterea, care indică o conexiune pierdută.

Expirarea timpilor de testare

fereastră zero.

Timpul de expirare a comenzii

conexiune ruptă.

472 conexiuni abandonate de keepalive

10.14 Respectarea cerințelor dezvoltatorului

Standardul TCP actual necesită ca implementările să adere la o procedură de pornire lentă la inițializarea unei conexiuni și să utilizeze algoritmii Kern și Jacobson pentru a estima timpul de retransmisie și pentru a gestiona încărcarea. Testele au arătat că aceste mecanisme conduc la îmbunătățiri semnificative ale performanței.

Ce se întâmplă dacă instalați un sistem care nu respectă aceste standarde? Nu va putea oferi performanțe adecvate propriilor utilizatori și va fi un vecin rău pentru alte sisteme din rețea, împiedicând restabilirea funcționării normale după congestie temporară și creând trafic excesiv care duce la căderea datagramelor.

10.15 Bariere în calea performanței

TCP și-a dovedit flexibilitatea, lucrând pe rețele cu rate de schimb de sute sau milioane de biți pe secundă. Acest protocol a făcut posibilă obținerea de rezultate bune în rețelele locale moderne cu topologii Ethernet, Token-Ring și Fibre Distributed Data Interface (FDDI), precum și pentru liniile de comunicație de viteză mică sau conexiunile la distanță lungă (cum ar fi legăturile prin satelit) .

TCP este conceput pentru a răspunde la condiții extreme, cum ar fi congestia rețelei. Cu toate acestea, versiunea actuală a protocolului are caracteristici care limitează performanța în tehnologiile promițătoare care oferă lățimi de bandă de sute și mii de megaocteți. Pentru a înțelege problemele care apar, luați în considerare un exemplu simplu (deși nerealist).

Să presupunem că atunci când mutați un fișier între două sisteme, doriți să schimbați un flux continuu cât mai eficient posibil. Să presupunem că:

■ Dimensiunea maximă a segmentului țintă este de 1 KB.

■ Fereastra de recepție - 4 KB.

Lățimea de bandă permite trimiterea a două segmente în 1 secundă.

■ Aplicația care primește consumă date la sosire.

Mesajele S ACK ajung în 2 secunde.

Expeditorul este capabil să trimită date în mod continuu. La urma urmei, când volumul alocat ferestrei este plin, ajunge un ACK, care permite trimiterea unui alt segment:

După 2 secunde:

PRIMI ACK A SEGMENTULUI 1, POATE TRIMITE SEGMENTUL 5.
PRIMI ACK A SEGMENTULUI 2, POATE TRIMITE SEGMENTUL 6.
PRIMI ACK A SEGMENTULUI 3, POATE TRIMITE SEGMENTUL 7.
PRIMI ACK A SEGMENTULUI 4, POATE TRIMITE SEGMENTUL 8.

După alte 2 secunde:

PRIMI ACK A SEGMENTULUI 5, POATE TRIMITE SEGMENTUL 9.

Dacă fereastra de recepție avea doar 2 KB, expeditorul ar trebui să aștepte o secundă din două înainte de a trimite următoarele date. De fapt, pentru a păstra un flux continuu de date, fereastra de recepție trebuie să fie cel puțin:

Fereastra = Lățime de bandă × Timp ciclu

Deși exemplul este oarecum exagerat (pentru a furniza numere mai simple), fereastra mică poate duce la probleme cu conexiunile prin satelit cu latență ridicată.

Acum să aruncăm o privire la ce se întâmplă cu conexiunile de mare viteză. De exemplu, dacă lățimea de bandă și rata de transfer sunt măsurate la 10 milioane de biți pe secundă, dar timpul ciclului este de 100 ms (1/10 dintr-o secundă), atunci pentru un flux continuu, fereastra de recepție trebuie să stocheze cel puțin 1.000.000 de biți, adică ... 125.000 de octeți. Dar cel mai mare număr care poate fi scris în câmpul antet pentru o fereastră de recepție TCP este 65.536.

O altă problemă apare la viteze de transfer mari, deoarece numerele de secvență se vor epuiza foarte repede. Dacă conexiunea poate transfera date la o viteză de 4 GB / s, atunci numerele de ordine trebuie actualizate în fiecare secundă. Nu va fi posibil să se facă distincția între datagramele vechi duplicate care au fost întârziate cu mai mult de o secundă pe măsură ce se deplasează pe Internet de date noi și noi.

Sunt în curs noi cercetări pentru îmbunătățirea TCP / IP și eliminarea barierelor de mai sus.

10.16 Funcții TCP

Acest capitol se concentrează pe numeroasele caracteristici ale TCP. Principalele sunt enumerate mai jos:

■ Legarea porturilor la conexiuni

■ Inițializarea conexiunilor prin confirmarea în 3 pași

■ Efectuează un pornire lentă pentru a evita congestia rețelei

■ Segmentarea datelor în tranzit

■ Numerotarea datelor

■ Gestionarea segmentelor duplicate primite

■ Calcularea sumelor de control

■ Reglarea fluxului de date prin fereastra de recepție și fereastra de trimitere

■ Încetarea conexiunii în modul stabilit

■ Întreruperea conexiunii

■ Transmiterea datelor urgente

■ Confirmare pozitivă a reexpedierii

■ Calculul timpului de retransmisie

■ Reducerea traficului de retur în timpul congestiei rețelei

■ Alarmă pentru sosirea în afara comenzii segmentului

■ Detectarea închiderii ferestrei de recepție

10.17 stări TCP

O conexiune TCP trece prin mai multe etape: conexiunea se stabilește prin schimbul de mesaje, apoi datele sunt trimise, iar apoi conexiunea este închisă folosind schimbul de mesaje speciale. Fiecare pas din activitatea conexiunii corespunde unui anumit condiție această legătură. Software-ul TCP de la fiecare capăt al conexiunii monitorizează constant starea curentă a celeilalte părți a conexiunii.

Mai jos vom analiza pe scurt o tranziție de stare tipică a serverului și clientului situate la diferite capete ale conexiunii. Nu intenționăm să oferim o descriere exhaustivă a tuturor stărilor posibile atunci când transferăm date. Se găsește în RFC 793 și document Cerințe de gazdă.

În timpul stabilirii conexiunilor, serverul și clientul trec prin secvențe de stări similare. Stările serverului sunt prezentate în Tabelul 10.3, iar stările clientului sunt prezentate în Tabelul 10.4.


Tabelul 10.3 Secvența stării serverului

Starea serverului Eveniment Descriere
ÎNCHIS (închis) O stare fictivă înainte de a începe o conexiune.
Deschidere pasivă prin aplicația server.
ASCULTĂ (urmărire) Serverul așteaptă o conexiune client.
Serverul TCP primește un SYN și trimite un SYN / ACK. Serverul a primit un SYN și a trimis un SYN / ACK. Merge să aștepte ACK.
SIN-PRIMIT Serverul TCP primește ACK.
STABILIT (instalat) ACK primit, conexiune deschisă.

Tabelul 10.4 Secvența stării clientului

Dacă partenerii ar încerca simultan să se conecteze între ei (ceea ce este extrem de rar), fiecare ar trece prin stările ÎNCHIS, SIN-SENT, SIN-RECEPTE și STABILIT.

Laturile finale ale conexiunii rămân în starea STABILITĂ până când una dintre părți începe închidere conexiuni prin trimiterea unui segment FIN. În timpul unei închideri normale, partea care inițiază această închidere trece prin stările prezentate în Tabelul 10.5. Partenerul ei trece prin stările prezentate în tabelul 10.6.


Tabelul 10.5 Secvența de stare a părții care închide conexiunea

Stări laterale de închidere Eveniment Descriere
STABILIT Aplicația locală solicită închiderea conexiunii.
TCP trimite FIN / ACK.
FIN-WAIT-1 Partidul de acoperire așteaptă răspunsul partenerului. Amintiți-vă că s-ar putea să sosească încă date noi de la partener.
TCP primește ACK.
FIN-WAIT-2 Partea finală a primit un ACK de la partener, dar FIN nu a sosit încă. Partea de închidere așteaptă un FIN, acceptând datele primite.
TCP primește FIN / ACK.
Trimite ACK.
TIMP DE AȘTEPTARE Conexiunea este menținută într-o stare nedeterminată pentru a permite duplicarea datelor sau FIN-urilor duplicate care încă există în rețea să ajungă sau să cadă. Perioada de așteptare este de două ori estimarea maximă a duratei de viață a segmentului.
ÎNCHIS

Tabelul 10.6 Secvența statelor partenere pentru a închide o conexiune

Statutul de partener Eveniment Descriere
STABILIT TCP primește FIN / ACK.
AȘTEPTĂ ÎNCHIS FIN a sosit.
TCP trimite ACK.
TCP așteaptă ca aplicația sa să închidă conexiunea. În acest moment, aplicația poate trimite o cantitate destul de mare de date.
Aplicația locală inițiază închiderea conexiunii.
TCP trimite FIN / ACK.
LAST-ACK TCP așteaptă ACK final.
TCP primește ACK.
ÎNCHIS Au fost eliminate toate informațiile de conexiune.

10.17.1 Analizarea stărilor conexiunii TCP

Comanda netstat -an vă permite să verificați starea curentă a conexiunii. Conexiunile în stări sunt prezentate mai jos ascultați, porniți, stabiliți, închidețiși timp de așteptare.

Rețineți că numărul portului de conexiune este listat la sfârșitul fiecărei adrese locale și externe. Puteți vedea că există trafic TCP atât pentru cozile de intrare, cât și pentru cele de ieșire.

Pro Recv-Q Trimite-Q Adresă locală Adresă străină (stat)
Tcp 0 0 128.121.50.145.25 128.252.223.5.1526 SYN_RCVD
Tcp 0 0 128.121.50.145.25 148.79.160.65.3368 STABILIT
Tcp 0 0 127.0.0.1.1339 127.0.0.1.111 TIME_WAIT
Tcp 0 438 128.121.50.145.23 130.132.57.246.2219 STABILIT
Tcp 0 0 128.121.50.145.25 192.5.5.1.4022 TIME_WAIT
Tcp 0 0 128.121.50.145.25 141.218.1.100.3968 TIME_WAIT
Tcp 0 848 128.121.50.145.23 192.67.236.10.1050 STABILIT
Tcp 0 0 128.121.50.145.1082 128.121.50.141.6000 STABILIT
Tcp 0 0 128.121.50.145.1022 128.121.50.141.1017 STABILIT
Tcp 0 0 128.121.50.145.514 128.121.50.141.1020 CLOSE_WAIT
Tcp 0 1152 128.121.50.145.119 192.67.239.23.3572 STABILIT
Tcp 0 0 128.121.50.145.1070 192.41.171.5.119 TIME_WAIT
Tcp 579 4096 128.121.50.145.119 204.143.19.30.1884 STABILIT
Tcp 0 0 128.121.50.145.119 192.67.243.13.3704 STABILIT
Tcp 0 53 128.121.50.145.119 192.67.236.218.2018 FIN_WAIT_1
Tcp 0 0 128.121.50.145.119 192.67.239.14.1545 STABILIT

10.18 Note de implementare

Încă de la început, TCP a fost conceput pentru interoperarea echipamentelor de rețea de la diferiți producători. Specificația TCP nu specifică exact cum ar trebui să funcționeze structurile de implementare interne. Aceste întrebări sunt lăsate dezvoltatorilor să găsească cele mai bune mecanisme pentru fiecare implementare specifică.

Chiar și RFC 1122 (document Cerințe pentru gazdă - cerințele gazdei) lasă suficient spațiu pentru variație. Fiecare dintre funcțiile implementate este marcată cu un anumit nivel de compatibilitate:

■ MAI (Permis)

■ NU TREBUIE

Din păcate, uneori există produse care nu implementează cerințele MUST. Ca urmare, utilizatorii experimentează degradarea performanței.

Unele bune practici de implementare nu sunt luate în considerare în standarde. De exemplu, îmbunătățirea securității este posibilă prin limitarea utilizării porturilor bine cunoscute prin procese de sistem privilegiate dacă această metodă este acceptată pe sistemul de operare local. Pentru a maximiza performanța, implementările ar trebui să aibă cât mai puține copii și mutări ale datelor trimise sau recuperate.

API standard nedefinit(precum și politica de securitate), astfel încât să existe un câmp gratuit pentru experimentarea cu diferite seturi de instrumente software. Cu toate acestea, acest lucru poate duce la utilizarea diferitelor API pe fiecare platformă și va împiedica mutarea software-ului aplicației între platforme.

De fapt, dezvoltatorii își bazează seturile de instrumente pe un API Socket împrumutat de la Berkeley. Importanța interfeței de programare a crescut odată cu apariția WINSock (Windows Socket), ceea ce a dus la o proliferare de noi aplicații desktop care ar putea rula deasupra oricărei interfețe WINSock compatibile cu stiva TCP / IP.

10.19 Lecturi suplimentare

Standardul TCP original este definit în RFC 793. Actualizările, remedierile și cerințele de compatibilitate sunt acoperite în RFC 1122. Kern și Partridge au publicat un articol Îmbunătățirea estimărilor dus-întors în protocoalele de transport fiabileÎn revistă Lucrările ACM SIGCOMM 1987. Articolul lui Jacobson Evitarea și controlul congestiei aparut in Lucrările atelierului ACM SIGCOMM 1988. Jacobson a emis, de asemenea, mai multe RFC-uri care revizuiesc algoritmi de îmbunătățire a performanței.



Ti-a placut articolul? Împărtășește-l