Aplicație tcp ip client server. Aplicație client-server pe un socket de flux TCP. Utilizări comune ale câmpurilor

Aplicație client-server pe un socket de flux TCP

Următorul exemplu utilizează TCP pentru a furniza fluxuri de octeți bidirecționale ordonate și fiabile. Să construim o aplicație completă care să includă un client și un server. Mai întâi, demonstrăm cum să construim un server folosind socket-uri de flux TCP și apoi o aplicație client pentru a testa serverul nostru.

Următorul program creează un server care primește cereri 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 cu clientul. 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 ( clasa Program ( static void Main(string args)) ( // Setați punctul final local pentru socket IPHostEntry ipHost = Dns.GetHostEntry("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = nou IPEndPoint(ipAddr, 11000); // Creați un socket Tcp/Ip Socket sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Atribuiți socket-ul la punctul final local și ascultați socketurile de intrare încercați ( sListener.Bind( ipEndPoint); sListener. Listen(10); // Începe să asculte pentru conexiuni în timp ce (adevărat) ( ​​Console.WriteLine ("Se așteaptă o conexiune pe portul (0)", ipEndPoint); // Programul se întrerupe, așteptând o conexiune de intrare Socket handler = sListener.Accept(); string data = null; // Am așteptat clientul care încearcă să se conecteze la noi byte bytes = new byte; int bytesRec = handler.Receive(bytes); data += Encoding. UTF8.GetString(bytes, 0, bytesRec); // Afișează datele pe consola Console.Write("Text primit: " + date + "\n\n"); // Trimiteți un răspuns către client\ string reply = "Vă mulțumim pentru cerere în " + data.Length.ToString() + " caractere"; byte msg = Encoding.UTF8.GetBytes(răspuns); handler.Send(msg); if (data.IndexOf(" ") > -1) ( Console.WriteLine("Serverul a încheiat conexiunea la client."); break; ) handler.Shutdown(SocketShutdown.Both); handler.Close(); ) ) catch (Excepție ex) ( Console.WriteLine (ex.ToString()); ) în cele din urmă ( Console.ReadLine(); ) ) ) )

Să ne uităm la structura acestui program.

Primul pas este să setați socket-ul la un punct final local. Înainte de a deschide o priză pentru a asculta conexiuni, trebuie să pregătiți o adresă de punct final local pentru aceasta. O adresă unică de service TCP/IP este determinată de combinația dintre adresa IP a gazdei cu numărul portului de service, care creează punctul final de service.

Clasa Dns oferă metode care returnează informații despre adresele de rețea acceptate de un dispozitiv din rețeaua locală. 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 adresa corespunzătoare pentru a o servi din matrice.

Să creăm un IPEndPoint pentru server combinând prima adresă IP a computerului gazdă obținută din metoda Dns.Resolve() cu numărul portului:

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

Aici clasa IPEndPoint reprezintă localhost pe portul 11000. În continuare, creăm un socket de flux cu o nouă instanță a clasei Socket. După ce am configurat un punct final local pentru a asculta conexiunile, putem crea un socket:

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

Transfer AdresăFamilie specifică schemele de adresare pe care o instanță a clasei Socket le poate folosi pentru a rezolva o adresă.

În parametru SocketType Socketurile TCP și UDP sunt diferite. În el puteți defini, printre altele, următoarele valori:

Dgram

Suporta datagrame. Valoarea Dgram necesită specificarea Udp pentru tipul de protocol și InterNetwork în parametrul familiei de adrese.

Brut

Acceptă accesul la protocolul de transport de bază.

Curent

Suportă prize de flux. Valoarea Stream necesită ca Tcp să fie specificat pentru tipul de protocol.

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

Următorul pas ar trebui să fie alocarea prizei folosind metoda Lega(). Când un socket este deschis de către un constructor, nu i se atribuie un nume, doar un handle este rezervat. Metoda Bind() este apelată pentru a atribui un nume socket-ului serverului. Pentru ca un socket client să identifice un socket de flux TCP, programul server trebuie să dea socket-ului un nume:

SListener.Bind(ipEndPoint);

Metoda Bind() leagă un socket la un punct final local. Metoda Bind() trebuie apelată înainte de orice încercare de a apela metodele Listen() și Accept().

Acum, după ce ai creat un socket și i-ai asociat un nume, poți asculta mesajele primite folosind metoda Asculta(). În starea de ascultare, soclul va asculta încercările de conectare de intrare:

SListener.Listen(10);

Parametrul definește restante, indicând numărul maxim de conexiuni care așteaptă în coadă. În codul de mai sus, valoarea parametrului permite să se acumuleze până la zece conexiuni în coadă.

În starea de ascultare, trebuie să fiți gata să acceptați să vă conectați cu clientul, pentru care este folosită metoda Accept(). Această metodă obține o conexiune client și finalizează asocierea numelui client și server. Metoda Accept() blochează firul de execuție al programului apelant până când ajunge o conexiune.

Metoda Accept() elimină prima cerere de conexiune din coada de cereri în așteptare și creează un nou socket pentru a o procesa. Deși este creat un nou socket, soclul original continuă să asculte și poate fi utilizat cu multi-threading pentru a accepta mai multe cereri de conexiune de la clienți. Nicio aplicație server nu ar trebui să închidă un soclu de ascultare. Trebuie să continue să funcționeze alături de socket-urile create prin metoda Accept pentru a procesa cererile primite de la clienți.

While (true) ( ​​​​Console.WriteLine("Se așteaptă o conexiune pe portul (0)", ipEndPoint); // Programul se întrerupe în timp ce așteaptă o conexiune de intrare Socket handler = sListener.Accept();

Odată ce clientul și serverul au stabilit o conexiune unul cu celălalt, mesajele pot fi trimise și primite folosind metodele Trimite()Și A primi() Clasa Priză.

Metoda Send() scrie datele de ieșire în soclul conectat. Metoda Receive() citește datele primite în soclul 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 comunică trebuie definit în prealabil pentru ca aplicațiile client și server să nu se blocheze reciproc neștiind cine ar trebui să-și trimită mai întâi datele.

Când schimbul de date între server și client este finalizat, 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 priză, A primi- oprește soclul să primească date și Trimite- oprește trimiterea de date prin socket.

Socket-ul este închis prin apelarea metodei Close(), care setează și proprietatea Connected a socket-ului la false.

Client TCP

Funcțiile care sunt folosite pentru a crea o aplicație client sunt mai mult sau mai puțin similare cu o aplicație server. Ca și în cazul serverului, aceleași metode sunt utilizate pentru a determina punctul final, a instanția socket-ul, a trimite și a primi date și a închide socket-ul.

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

TCP și UDP sunt ambele protocoale de nivel 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 livrarea de pachete garantată. Mai întâi are loc o strângere de mână (Bună. | Bună. | Să discutăm? | Să mergem.), după care conexiunea se consideră stabilită. Apoi pachetele sunt trimise înainte și înapoi prin această conexiune (o conversație este în curs) și se verifică dacă pachetul a ajuns la destinatar. Dacă pachetul este pierdut sau a sosit, dar cu o sumă de control ruptă, atunci este trimis din nou („repetă, nu am auzit”). Astfel, TCP este mai fiabil, dar este mai complex din punct de vedere al implementării și, în consecință, necesită mai multe cicluri de ceas/memorie, ceea ce nu este cel mai puțin important pentru microcontrolere. Exemple de protocoale de aplicație 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 utilizat pe scară largă pe World Wide Web pentru a prelua informații de pe site-uri web. Imaginea prezintă o lampă pe un microcontroler cu un sistem de operare la bord, în care culorile sunt setate printr-un browser.

Protocolul HTTP este bazat pe text și destul de simplu. De fapt, așa arată metoda GET, trimisă de utilitarul netcat la adresa IPv6 locală a serverului cu lumini:

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

Metoda HTTP este de obicei un cuvânt scurt englezesc scris cu majuscule și ține seama de majuscule. Fiecare server trebuie să accepte cel puțin metodele GET și HEAD. Pe lângă metodele GET și HEAD, se folosesc adesea metodele POST, PUT și DELETE. Metoda GET este folosită pentru a solicita conținutul unei resurse specificate, în cazul nostru aici GET /b HTTP/1.0 unde calea /b este responsabilă pentru culoare (albastru). Răspunsul serverului:

HTTP/1.0 200 OK Server: Contiki/2.4 http://www.sics.se/contiki/ Conexiune: închide Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expire: 0 Content- tip: text/html Contiki RGB

Roșu este OPRIT

Verdele este OPRIT

Albastrul este pornit

Codul de stare (avem 200) face parte din prima linie a răspunsului serverului. Este un număr întreg de 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 particular. În cazul nostru, serverul a funcționat fără erori, totul a fost bine (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ă prin două puncte). Anteturile se termină cu o linie goală, după care pot urma datele.

Browserul meu refuză să deschidă adresa IPv6 locală, așa că 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 într-un mediu client/server (vezi Figura 10.1). Aplicație server gandaci(ascultați) solicitările de conectare primite. De exemplu, WWW, transferul de fișiere sau serviciile de acces la terminale ascultă cererile venite de la clienți. Comunicațiile în TCP sunt inițiate de rutine adecvate, care inițiază o conexiune la server (vezi Capitolul 21 despre 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 trimite mesaje de e-mail între computere.

10.2 Concepte TCP

În ce formă ar trebui aplicațiile să trimită date în TCP? În ce formă transmite TCP date către IP? Cum identifică protocoalele TCP de trimitere și de primire conexiunea dintre aplicații și elementele de date necesare implementării acesteia? La toate aceste întrebări se răspunde în următoarele secțiuni, care descriu conceptele de bază ale TCP.

10.2.1 Fluxuri de date de intrare și ieșire

Conceptual Modelul de conexiune implică o aplicație care transmite un flux de date către o aplicație 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) modul de operare în care service simultan două fluxuri date (vezi Fig. 10.2).


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

10.2.2 Segmente

TCP poate converti fluxul de date care părăsește o aplicație într-o formă adecvată pentru a fi stocată în datagrame. Cum?

Aplicația trimite date către TCP, iar acest protocol le plasează tampon de ieșire(trimite buffer). Apoi, TCP taie bucăți de date din buffer și le trimite, adăugând un antet (acest lucru generează segmente- segment). În fig. 10.3 arată cum datele de la tampon de ieșire TCP este pachetat în segmente. TCP transmite segmentul către IP pentru livrare ca datagramă separată. Pachetarea datelor în bucăți de lungime corectă asigură o redirecționare eficientă, astfel încât TCP va aștepta până când cantitatea adecvată de date este disponibilă în tamponul de ieșire înainte de a crea un segment.


Orez. 10.3 Crearea unui segment TCP

10.2.3 Împingere

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 al utilizatorului final inițiază o sesiune interactivă cu un server la distanță, utilizatorul introduce doar comenzi (urmate de apăsarea tastei Întoarcere).

Programul client al utilizatorului are nevoie de TCP pentru a ști că datele sunt trimise către gazda de la distanță și pentru a efectua această operație imediat. În acest caz se folosește împingând afară(Apăsaţi).

Dacă te uiți la operațiunile dintr-o sesiune interactivă, vei găsi multe segmente cu puține date și, în plus, popping poate fi găsit în aproape fiecare segment de date. Cu toate acestea, împingerea nu ar trebui utilizată în timpul transferurilor de fișiere (cu excepția ultimului segment), iar TCP va putea să împacheteze datele în segmente cel mai eficient.

10.2.4 Date urgente

Modelul de redirecționare a datelor al aplicației implică un flux ordonat de octeți care călătoresc la destinație. Referindu-ne din nou la exemplul de sesiune interactivă, să presupunem că utilizatorul a apăsat o tastă Atenţie(atentie) sau pauză(întrerupe). Aplicația de la distanță trebuie să poată sări peste octeții care interferează și să răspundă la apăsarea tastei cât mai repede posibil.

Mecanism date urgente(date urgente) marchează informații speciale într-un segment ca urgent. Făcând acest lucru, TCP îi spune egalului său că segmentul conține date urgente și poate indica unde se află. Partenerul trebuie să transmită aceste informații către aplicația 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 realizează prin specificarea adresei IP a serviciului gazdă și a numărului său de port TCP. La fel ca UDP, numerele de porturi TCP variază de la 0 la 65535. Porturile din intervalul 0 la 1023 sunt numite binecunoscute și sunt folosite pentru a accesa serviciile standard.

Câteva exemple de porturi binecunoscute și aplicațiile lor corespunzătoare sunt prezentate în Tabelul 10.1. Servicii Aruncă(portul 9) și taxat(portul 19) sunt versiuni TCP ale serviciilor deja cunoscute de noi prin UDP. Trebuie reținut că traficul către portul 9 al protocolului TCP este complet izolat de traficul către portul 9 al protocolului UDP.


Tabelul 10.1 Porturi TCP binecunoscute și aplicațiile lor corespunzătoare

Port Aplicație Descriere
9 Aruncă Anulați toate datele primite
19 Încărcat Generator de caractere. Schimb de caractere
20 Date FTP Port de redirecționare a datelor FTP
21 FTP Port pentru dialog FTP
23 TELNET Port pentru înregistrarea de la distanță prin Telnet
25 SMTP Port protocol SMTP
110 POP3 Serviciu de eșantionare prin e-mail pentru computere personale
119 NNTP Acces la știri online

Dar porturile folosite de clienți? În cazuri rare, clientul nu lucrează printr-un port binecunoscut. Dar în astfel de situații, dorind să deschidă o conexiune, de multe ori îi cere sistemului de operare să îi atribuie un port neutilizat și nerezervat. La sfârșitul conexiunii, clientul trebuie să returneze acest port, după care portul poate fi reutilizat de un alt client. Deoarece există mai mult de 63.000 de porturi TCP în pool-ul de numere nerezervate, restricțiile de port client pot fi ignorate.

10.2.6 Adrese de socket

După cum știm deja, este numită combinația dintre adresa IP și portul pentru comunicare priza de adresa. O conexiune TCP este complet identificată prin adresa socketului de la fiecare capăt al conexiunii. În fig. Figura 10.4 prezintă conexiunea dintre un client cu adresă socket (128.36.1.24, port = 3358) și un server cu adresă socket (130.42.88.22, port = 21).

Orez. 10.4. Adrese de socket

Antetul fiecărei datagrame conține adresele IP sursă și destinație. Veți vedea mai târziu că numerele portului sursă și destinație sunt specificate în antetul segmentului TCP.

De obicei, un server este capabil să gestioneze mai mulți clienți simultan. Adresele unice de socket de server sunt atribuite simultan tuturor clienților săi (vezi Fig. 10.5).


Orez. 10.5. Clienți multipli conectați la adrese de socket de server

Deoarece o datagramă conține un segment de conexiune TCP identificat prin adrese IP și porturi, este foarte ușor pentru un server să țină evidența conexiunilor multiple la clienți.

10.3 Mecanismul de fiabilitate TCP

În această secțiune, ne vom uita la mecanismul TCP utilizat pentru a furniza în mod fiabil datele, păstrând în același timp ordinea de transmisie și evitând pierderea sau duplicarea.

10.3.1 Numerotarea și confirmarea

TCP utilizează numerotarea și confirmarea (ACK) pentru a asigura un transfer de date fiabil. Schema de numerotare TCP este oarecum neobișnuită: fiecare transmis prin conexiune octet este considerat a avea un număr de serie. Antetul segmentului TCP conține un număr de secvență primul octet de date din acest segment.

Destinatarul trebuie să confirme că datele au fost primite. Dacă ACK-ul nu ajunge în intervalul de timeout, datele sunt retransmise. Această metodă se numește confirmare pozitivă cu releu(confirmare pozitivă cu retransmisie).

Destinatarul datelor TCP verifică strict numerele de secvență de intrare pentru a verifica dacă datele sunt primite în ordine și că nu lipsesc părți. Deoarece ACK-ul poate fi pierdut sau întârziat aleatoriu, segmentele duplicat pot ajunge la destinatar. Numerele de secvență vă permit să identificați datele duplicate, care sunt apoi aruncate.

În fig. Figura 10.6 prezintă o vedere simplificată a timeout-ului și retransmisiei în TCP.


Orez. 10.6. Timeout și retransmisie în TCP

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

După cum se arată în Fig. 10.7, primele câteva câmpuri ale antetului TCP oferă spațiu pentru valorile portului sursă și destinație, numărul de secvență al primului octet al datelor incluse și un ACK egal cu numărul de secvență 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 la egalul său, acest câmp va avea valoarea 31, indicând segmentul de redirecționat următor.


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

Un mic detaliu nu poate fi trecut cu vederea. Să presupunem că TCP a trimis octeții de la 1 la 50 și nu mai sunt date de trimis. Dacă datele sunt primite de la un peer, TCP trebuie să confirme primirea lor prin trimiterea unui antet fără datele atașate acestuia. Desigur, acest antet conține valoarea ACK. În câmpul secvență - valoarea este 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, un câmp de secvență de 51.

10.4 Stabilirea unei conexiuni

Cum se conectează două aplicații una la alta? Înainte de comunicare, fiecare dintre ei apelează o subrutină pentru a forma un bloc de memorie care va fi folosit pentru a stoca parametrii TCP și IP ai unei conexiuni date, de exemplu, adrese de socket, numărul de secvență curent, valoarea inițială a duratei de viață etc.

Aplicația server așteaptă să apară un client care, dorind să aibă acces la server, emite o cerere de compus(conectare), identificând adresa IP și portul serverului.

Există o caracteristică tehnică. Fiecare parte începe să numeroteze fiecare octet nu cu unul, ci cu număr de serie aleatoriu(vom afla mai târziu de ce se face acest lucru). Specificația originală recomandă ca numărul de secvență inițial să fie generat pe baza unui temporizator extern de 32 de biți care crește aproximativ la fiecare 4 µs.

10.4.1 Scenariul conexiunii

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

În timpul stabilirii conexiunii, partenerii fac schimb de trei informații importante:

1. Spațiu tampon pentru primirea datelor

2. Cantitatea maximă de date transportate într-un segment de intrare

3. Numărul secvenței de pornire utilizat pentru datele trimise

Rețineți că fiecare parte folosește operațiunile 1 și 2 pentru a indica limitele în care cealaltă parte va acționa. Un computer personal poate avea un buffer de primire mic, dar un supercomputer poate avea un buffer mare. Structura de memorie a unui computer personal poate limita bucățile de date primite la 1 KB, dar un supercomputer gestionează segmente mai mari.

Abilitatea de a controla modul în care cealaltă parte trimite datele este o caracteristică importantă care face ca TCP/IP să fie scalabil.

În fig. Figura 10.8 prezintă un exemplu de script de conexiune. Sunt prezentate numere de succesiune inițiale foarte simple pentru a nu supraîncărca desenul. Rețineți că în această figură, clientul este capabil să primească segmente mai mari decât serverul.


Orez. 10.8. Stabilirea unei conexiuni

Se efectuează următoarele operații:

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

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

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

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

5. Clientul TCP, după ce a primit un mesaj SYN/ACK de la server, trimite înapoi ACK 3001 (primul octet de date trimis de server ar trebui să fie numerotat 3001).

6. Clientul TCP solicită aplicației sale să deschidă conexiunea.

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

Clientul și serverul își anunță regulile pentru datele primite, își sincronizează numerele de secvență ș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 de la egal la egal se deschid simultan în mod activ reciproc.

10.4.2 Setarea valorilor parametrilor IP

O cerere de aplicație pentru a stabili o conexiune poate specifica, de asemenea, parametrii pentru datagramele IP care vor transporta datele de conexiune. Dacă nu este specificată o anumită valoare a parametrului, se utilizează valoarea implicită.

De exemplu, o aplicație poate selecta o valoare 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ă se folosesc aceleași valori pentru fiecare direcție de schimb.

Când o aplicație implică opțiuni de securitate guvernamentală sau militară, fiecare punct final al 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 Figura 10.9). Standardul TCP permite ca date normale să fie incluse în segmentele de confirmare, dar nu vor fi livrate aplicației până la finalizarea conexiunii. Pentru a simplifica numerotarea, sunt folosite mesaje de 1000 de octeți. Fiecare segment de antet TCP are un câmp ACK care identifică numărul de secvență de octeți care se așteaptă să fie primit de la partenerul de conexiune.


Orez. 10.9. Schimb simplu de date și flux 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ă valoarea 3001, care indică numărul secvenței de octeți care se așteaptă să fie primit de la server.

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

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

Serverul salvează lățimea de bandă a conexiunii utilizând un singur ACK pentru a indica succesul în redirecționarea tuturor segmentelor.

În fig. Figura 10.10 arată transferul de date atunci când primul segment este pierdut. Când expiră timpul de expirare, segmentul este retransmis. Rețineți că la primirea unui segment pierdut, receptorul trimite un singur ACK care confirmă redirecționarea ambelor segmente.


Orez. 10.10. Pierderea și retransmiterea datelor

10.6 Închiderea unei conexiuni

Încetarea normală a unei conexiuni se realizează utilizând aceeași procedură de strângere de mână triplă ca la deschiderea unei conexiuni. Fiecare parte poate începe să închidă conexiunea utilizând următorul scenariu:

A:

B:"Amenda".

ÎN:„Am terminat și eu treaba.”

A:"Amenda".

Să presupunem următorul scenariu (deși este folosit extrem de rar):

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

ÎN:"Bine. Cu toate acestea, există câteva date..."

ÎN:„Am terminat și eu treaba.”

A:"Amenda".

În exemplul de mai jos, conexiunea este închisă de către server, așa cum este adesea cazul conexiunilor client/server. În acest caz, după ce utilizatorul intră în sesiune telnet Comanda de deconectare determină serverul să inițieze o solicitare de închidere a conexiunii. În situația prezentată în fig. 10.11, se efectuează următoarele acțiuni:

1. Aplicația de pe server îi spune TCP să închidă conexiunea.

2. Serverul TCP trimite un segment final (Final Segment - FIN), informând egalul său că nu mai sunt date de trimis.

3. TCP-ul clientului trimite un ACK în segmentul FIN.

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

5. Aplicația client îi spune TCP să închidă conexiunea.

6. Clientul TCP trimite un mesaj FIN.

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

8. TCP-ul serverului spune aplicației sale 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 peer trimite un mesaj ACK.

10.6.1 Încetarea bruscă

Fiecare parte poate solicita o întrerupere bruscă (închidere bruscă) a conexiunii. Acest lucru este acceptabil atunci când o aplicație dorește să încheie o conexiune sau când TCP detectează o problemă gravă de comunicare pe care nu o poate rezolva prin mijloace proprii. Terminarea bruscă este solicitată prin trimiterea unuia sau mai multor mesaje de resetare către peer, indicate de un indicator specific în antetul TCP.

10.7 Controlul debitului

Receptorul TCP este încărcat cu fluxul de date primit și determină câte informații poate accepta. Această limitare afectează expeditorul TCP. Următoarea explicație a acestui mecanism este conceptuală, iar dezvoltatorii o pot implementa în moduri diferite în produsele lor.

În timpul configurării conexiunii, fiecare peer alocă spațiu pentru buffer-ul de intrare al conexiunii și notifică cealaltă parte despre aceasta. De obicei, dimensiunea tamponului este exprimată ca un număr întreg al dimensiunilor maxime ale segmentului.

Fluxul de date intră în buffer-ul de intrare și este stocat acolo înainte de a fi redirecționat către aplicație (definit de portul TCP). În fig. Figura 10.12 prezintă un buffer de intrare care poate accepta 4 KB.


Orez. 10.12. Fereastra de primire a tamponului de intrare

Spațiul tampon este umplut pe măsură ce sosesc datele. Când aplicația de primire preia date din buffer, spațiul eliberat devine disponibil pentru noi date primite.

10.7.1 Fereastra de primire

Fereastra de recepție(fereastră de primire) - orice spațiu din buffer-ul de intrare care nu este deja ocupat de date. Datele rămân în memoria tampon de intrare până când sunt utilizate de aplicația țintă. De ce aplicația nu colectează date imediat?

Un scenariu simplu vă va ajuta să răspundeți la această întrebare. Să presupunem că un client a trimis un fișier către un server FTP care rulează pe un computer cu mai mulți utilizatori foarte ocupat. Programul FTP trebuie apoi să citească datele din buffer și să le scrie pe disc. Când serverul efectuează operațiuni I/O pe disc, programul așteaptă finalizarea acelor operațiuni. Î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 confirmat până la sfârșitul bufferului. În fig. 10.12, mai întâi este disponibil întregul buffer și, prin urmare, este disponibilă o fereastră de primire de 4 KB. Când sosește primul KB, fereastra de primire se va reduce la 3 KB (pentru simplitate, vom presupune că fiecare segment are o dimensiune 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 primire 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 reglat fluxul de date de la sursă.

În cea mai mare parte, dimensiunea bufferului de intrare este setată la pornirea conexiunii, deși standardul TCP nu specifică modul de gestionare a acestui buffer. Buffer-ul de intrare poate fi mărit sau micșorat prin furnizarea de feedback expeditorului.

Ce se întâmplă dacă segmentul care sosește poate fi plasat în fereastra de recepție, dar ajunge în neregulă? În general, se presupune că toate implementările stochează datele primite într-o fereastră de primire și trimit o confirmare (ACK) numai pentru întregul bloc contiguu de mai multe segmente. Aceasta este modalitatea corectă, deoarece, în caz contrar, eliminarea datelor care ajung în neregulă va reduce semnificativ performanța.

10.7.2 Fereastra de trimitere

Sistemul care transmite date trebuie să țină evidența a două caracteristici: câte date au fost deja trimise și confirmate și dimensiunea curentă a ferestrei de primire a destinatarului. Activ spatiu de trimitere(spațiul de trimitere) se extinde de la primul octet neconfirmat până la marginea stângă a ferestrei de recepție curente. Parte fereastră, folosit a trimite, indică câte date suplimentare pot fi trimise partenerului.

Numărul de secvență inițial și dimensiunea inițială a ferestrei de primire sunt specificate în timpul configurării conexiunii. Orez. Figura 10.13 ilustrează unele dintre caracteristicile mecanismului de transfer de date.

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

2. Expeditorul trimite 1 KB. O copie a acestor date este păstrată până când se primește o confirmare (ACK), deoarece poate fi necesar să fie retransmise.

3. Sosește mesajul ACK pentru primul KB și sunt trimiși următorii 2 KB de date. 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ă, sosește un ACK pentru toate datele transmise (adică, toate acestea sunt primite de receptor). ACK restabilește dimensiunea ferestrei de trimitere la 4 KB.

Orez. 10.13. Fereastră de trimitere

Există câteva caracteristici interesante care merită subliniate:

■ Expeditorul nu așteaptă un ACK pentru fiecare segment de date pe care îl trimite. Singura restricție privind redirecționarea este dimensiunea ferestrei de primire (de exemplu, expeditorul trebuie să redirecționeze doar segmente de un singur octet de 4K).

■ 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. Figura 10.14 prezintă formatul segmentului (antetul 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 de secvență) indică poziția în fluxul de date de ieșire pe care o ocupă acest segment. Camp ACK(confirmare) conține informații despre următorul segment așteptat care ar trebui să apară în fluxul de date de intrare.


Orez. 10.14. Segmentul TCP

Există șase steaguri:

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

10.8.1 Opțiunea pentru dimensiunea maximă a segmentului

Parametru „dimensiunea maximă a segmentului”(dimensiunea maximă a segmentului - MSS) este utilizat pentru a declara cea mai mare bucată de date care poate fi acceptată și procesată de sistem. Cu toate acestea, numele este oarecum inexact. De obicei în TCP segment tratate ca antet plus date. in orice caz dimensiunea maximă a segmentului definit ca:

Dimensiunea celei mai mari datagrame care poate fi primită este de 40

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

Valoarea declarată MSS + 40 – (suma lungimilor antetului TCP și IP)

Peers schimbă de obicei valori MSS în mesajele SYN inițiale atunci când deschid o conexiune. Dacă sistemul nu face publicitate unei valori de dimensiune maximă a segmentului, se utilizează valoarea implicită de 536 de octeți.

Dimensiunea maximă a segmentului este codificată ca o intrare de 2 octeți urmată de o valoare de 2 octeți, de exemplu. cea mai mare valoare va fi 2 16 -1 (65.535 octeți).

MSS impune o limitare severă asupra datelor trimise în TCP: receptorul nu va putea procesa valori mari. Cu toate acestea, expeditorul folosește segmente dimensiuni mai mici, deoarece dimensiunea MTU de-a lungul traseului este determinată și pentru conexiune.

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

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 cu o valoare de 0. Rețineți că instrumentele de securitate folosesc această caracteristică pentru a identifica cererile de intrare pentru o sesiune TCP.

Camp număr de serie conţine numărul de ordine inițial(număr de ordine inițial), câmp fereastră - dimensiunea initiala fereastra de recepție. Singurul parametru TCP definit în prezent este dimensiunea maximă a segmentului (când nu este specificată, este utilizată valoarea implicită de 536 de octeți) pe care TCP se așteaptă să o primească. Această valoare ocupă 32 de biți și este de obicei prezentă în cererea de conectare din 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 într-un răspuns la cererea de conexiune

Într-un răspuns de acordare la o solicitare de conexiune, ambele indicatoare (SYN și ACK) sunt egale cu 1. Sistemul care răspunde indică numărul secvenței de pornire în câmpul corespunzător și dimensiunea ferestrei de primire î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 cererea de conectare (în Opțiuni). Această valoare poate diferi 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 de ordine de pornire

Specificația TCP presupune că în timpul configurării conexiunii fiecare parte alege numărul de ordine inițial(pe baza valorii curente a temporizatorului intern pe 32 de biți). Cum se face asta?

Să ne imaginăm ce se va întâmpla dacă sistemul se prăbușește. Să presupunem că utilizatorul a deschis o conexiune chiar înainte de accident ș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 accident, inclusiv conexiunile deja începute și numerele de porturi atribuite. Utilizatorul restabilește conexiunea. Numerele porturilor nu se potrivesc cu atribuirile originale, iar unele dintre ele pot fi deja utilizate de alte conexiuni stabilite cu câteva secunde înainte de accident.

Prin urmare, cealaltă parte aflată la sfârșitul conexiunii poate să nu știe că partenerul său s-a prăbușit și a fost apoi restabilit. Toate acestea vor duce la întreruperi serioase, mai ales când este nevoie de mult timp pentru ca datele vechi să treacă prin rețea și să se amestece cu datele din conexiunea nou creată. Selectarea unui temporizator de pornire cu o actualizare (pornire nouă) elimină astfel de probleme. Datele vechi vor avea o numerotare diferită de intervalul de numere de secvență 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ță inițial previzibil în mesaj. O funcție de hashing criptografic bazată pe chei interne oferă cea mai bună metodă de selectare a semințelor securizate.

10.8.5 Utilizări comune ale 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 de serie(Număr de secvență).

Numărul următorului 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ă(Fereastra) este destinat dimensiunii curente a ferestrei de recepție. Acest câmp conține numărul de octeți din numărul de confirmare care pot fi primiți. Rețineți că această valoare permite controlul precis al fluxului de date. Folosind această valoare, peer-ul indică starea reală a ferestrei de primire în timpul sesiunii de schimb.

Dacă o aplicație specifică o operațiune de împingere în TCP, atunci indicatorul PUSH este setat la 1. TCP-ul de primire TREBUIE să răspundă la acest indicator prin livrarea rapidă a datelor către aplicație de îndată ce expeditorul dorește să le transmită.

Indicatorul URGENT, atunci când este setat la 1, implică transfer de date urgent, iar indicatorul corespunzător trebuie să se refere la ultimul octet al datelor urgente. O utilizare tipică a datelor urgente este trimiterea de semnale de renunțare sau renunțare de la terminal.

Datele urgente sunt adesea numite informații în afara benzii(în afara benzii). Cu toate acestea, acest termen este imprecis. Datele urgente sunt trimise într-un flux TCP normal, deși implementările individuale 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 de mesaj să fi sosit.

Indicatorul RESET este setat la 1 atunci când conexiunea ar trebui să se termine anormal. Același steag este setat în răspuns când sosește un segment care nu este asociat cu niciuna dintre conexiunile TCP curente.

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


10.8.6 Sumă de control

Suma de verificare IP este doar pentru antetul IP, în timp ce suma de control TCP este calculată pentru întregul segment, precum și pentru pseudo-antetul creat din antetul IP. În timpul calculului sumei de control TCP, câmpul corespunzător are valoarea 0. În Fig. Figura 10.15 prezintă un pseudo-antet care seamănă foarte mult cu cel utilizat într-o sumă de control 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 la lungimea datelor. Suma de control TCP este obligatoriu, nu ca UDP. Suma de control a unui segment care sosește este mai întâi calculată de către receptor și apoi comparată cu conținutul câmpului sumă de control antet TCP. Dacă valorile nu se potrivesc, segmentul este eliminat.

10.9 Exemplu de segment TCP

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


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

Analizor Mirositoare convertește majoritatea valorilor în formă zecimală. Cu toate acestea, valorile steagului sunt afișate ca hexazecimal. Un indicator cu o valoare de 12 reprezintă 010010. Suma de control este, de asemenea, scoasă în format hexazecimal.

10.10 Suport sesiune

10.10.1 Sondarea ferestrei

Un expeditor rapid și un receptor lent pot forma o fereastră de primire de dimensiunea 0 octeți. Acest rezultat se numește închizând fereastra(fereastră închisă). Când spațiul liber devine disponibil pentru a actualiza dimensiunea ferestrei de primire, se folosește ACK. Cu toate acestea, dacă un astfel de mesaj este pierdut, ambele părți vor trebui să aștepte la nesfârșit.

Pentru a evita această situație, expeditorul stabilește temporizator salvabil(temporizator persistent) la închiderea ferestrei temporare. Valoarea temporizatorului este timpul de expirare a retransmisiei. La finalizarea cronometrului, un segment este trimis partenerului detectarea ferestrei(sonda fereastră; unele implementări includ și date). Probarea face ca peer-ul să trimită înapoi un ACK care raportează starea curentă a ferestrei.

Dacă fereastra rămâne în continuare la dimensiunea zero, valoarea temporizatorului salvat este dublată. Acest proces se repetă până când cronometrul atinge maximum 60 de secunde. TCP va continua să trimită mesaje de sondă la fiecare 60 de secunde până când se deschide fereastra, utilizatorul încheie procesul sau până când aplicația expiră.

10.11 Încheierea unei sesiuni

10.11.1 Time-out

Partenerul de conexiune se poate bloca sau poate fi complet întrerupt din cauza unui gateway sau a unei legături defecte. Pentru a preveni retransmiterea datelor în TCP, există mai multe mecanisme.

Când TCP atinge primul prag de retransmisie, îi spune IP să verifice routerul eșuat și informează simultan aplicația că există o problemă. TCP continuă să trimită date până când este atins al doilea prag înainte de a elibera conexiunea.

Desigur, înainte să se întâmple acest lucru, poate sosi un mesaj ICMP care indică faptul că destinația este inaccesibilă dintr-un motiv oarecare. În unele implementări, chiar și după aceasta, TCP va continua să încerce să acceseze destinația până când intervalul de timeout expiră ( moment în care problema poate fi remediată). Apoi, aplicația este informată că punctul de destinație este inaccesibil.

O aplicație își poate seta propriul timeout pentru livrarea datelor și își poate efectua propriile operațiuni atunci când acest interval se termină. De obicei, conexiunea este întreruptă.

10.11.2 Menținerea unei conexiuni

Când o conexiune incompletă are date de redirecționat pentru o perioadă lungă de timp, aceasta devine inactivă. În timpul unei perioade de inactivitate, rețeaua se poate prăbuși sau liniile de comunicații fizice pot fi întrerupte. 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 respectat cerințele Ministerului Apărării.

Cu toate acestea, orice conexiune - activă sau inactivă - ocupă multă memorie de calculator. Unii administratori trebuie să returneze sistemelor resursele neutilizate. Prin urmare, multe implementări TCP sunt capabile să trimită un mesaj despre menținerea conexiunii(keep-alive), care testează conexiunile inactive. Astfel de mesaje sunt trimise periodic partenerului pentru a verifica existența acestuia în rețea. Răspunsul ar trebui să fie mesaje ACK. Utilizarea mesajelor de menținere în viață este opțională. Dacă sistemul are această capacitate, aplicația o poate suprascrie folosind propriile mijloace. Perioada estimată Mod implicit Timpul de întreținere a conexiunii este de două ore!

Să ne amintim că o aplicație își poate seta propriul cronometru, în funcție de care va decide la propriul nivel dacă va termina conexiunea.

10.12 Performanţă

Cât de eficient este TCP? Performanța resurselor este afectată de mulți factori, principalii fiind memoria și lățimea de bandă (vezi Figura 10.17).


Orez. 10.17. Factori de performanță TCP

Lățimea de bandă și latența rețelei fizice utilizate limitează semnificativ debitul. Calitatea slabă a transmiterii datelor are ca rezultat un volum mare de datagrame aruncate, ceea ce provoacă retransmisii și, în consecință, reduce eficiența lățimii de bandă.

Capătul de recepție 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ță mare, unde există un interval de timp lung între trimiterea datelor și primirea unui ACK (și atunci când negociați dimensiunea unei ferestre). Pentru a menține un flux constant de date de la sursă, capătul de recepție trebuie să aibă o fereastră de cel puțin dimensiunea produsului lățime de bandă și latență.

De exemplu, dacă sursa poate trimite date la o rată de 10.000 de octeți/s, iar ACK-ul durează 2 secunde pentru a reveni, atunci cealaltă parte trebuie să furnizeze o fereastră de recepție de cel puțin 20.000 de octeți în dimensiune, altfel fluxul de date nu va fi continuu. Un buffer 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 schimbarea contextului, adică finalizați unele operații și treceți la altele. Gazda poate susține interactiv mai mulți utilizatori locali, procese în fundal în loturi și zeci de conexiuni de comunicare simultane. Comutarea contextului vă permite să gestionați toate aceste operațiuni în timp ce ascundeți încărcarea sistemului. Implementările care integrează TCP/IP cu nucleul sistemului de operare pot reduce semnificativ sarcina utilizării comutării contextului.

Resurse CPU sunt necesare pentru operațiunile de procesare a antetului TCP. Dacă procesorul nu poate calcula rapid sumele de control, aceasta duce la o scădere a vitezei de transfer de date în rețea.

În plus, dezvoltatorii ar trebui să caute să simplifice configurarea setărilor TCP, astfel încât administratorul de rețea să le poată configura pentru a se potrivi cerințelor locale. De exemplu, capacitatea de a ajusta dimensiunea bufferului la lățimea de bandă a rețelei și latența va îmbunătăți semnificativ performanța. Din păcate, multe implementări nu acordă suficientă atenție acestei probleme și programează rigid parametrii de comunicare.

Să presupunem că mediul de rețea este perfect: există resurse suficiente și schimbarea contextului se realizează mai rapid decât cowboy-ul care își scot revolverele. Se vor obține performanțe excelente?

Nu intotdeauna. Contează și calitatea dezvoltării software TCP. De-a lungul anilor, multe probleme de performanță au fost diagnosticate și rezolvate în diferite implementări TCP. Se poate considera că cel mai bun software va fi unul care respectă RFC 1122, care definește cerințele pentru nivelul de comunicare al gazdelor Internet.

La fel de importantă este și excepția și utilizarea 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 cronometre încorporate pentru a elibera resursele de rețea care nu sunt utilizate în prezent.

10.13 Algoritmi pentru îmbunătățirea performanței

Trecând mai departe pentru a cunoaște partea destul de complexă a TCP, ne vom uita la mecanismele de creștere a performanței și de rezolvare a problemelor cu debit redus. Această secțiune discută următoarele probleme:

Pornire lent(pornire lentă) împiedică utilizarea unei mari părți a traficului de rețea pentru o nouă sesiune, ceea ce poate duce la risipă.

■ Vindecare de sindromul „fereastră fără idee”.(sindromul ferestrei prostești) împiedică aplicațiile prost proiectate să supraîncărce rețeaua cu mesaje.

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

Timeout de retransmisie calculat(timeout de retransmisie de calcul) se bazează pe negocierea timpului real de sesiune, reducând cantitatea de retransmisii inutile, dar nu provoacă întârzieri mari pentru schimburile de date cu adevărat necesare.

■ Inhibarea redirecționării TCP când suprasarciniîntr-o rețea permite routerelor să revină la modul lor original și să partajeze resursele de rețea în toate sesiunile.

■ Expediere ACK-uri duplicat(ACK duplicat) atunci când se primește un segment în afara secvenței, permite colegilor să retransmită înainte de expirarea timpului.

10.13.1 Pornire lentă

Dacă porniți toate aparatele electrocasnice de acasă în același timp, rețeaua electrică va fi supraîncărcată. În rețelele de calculatoare pornire lent previne arderea siguranțelor de la rețea.

O nouă conexiune care începe instantaneu să trimită o cantitate mare de date într-o rețea deja ocupată poate duce la probleme. Ideea unui start lent este de a vă asigura că o nouă conexiune pornește cu succes, î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 de primire mai mare.

Fereastra de încărcare(fereastră de congestie) începe cu o dimensiune de 1 segment. Pentru fiecare segment cu un ACK primit cu succes, dimensiunea ferestrei de încărcare este mărită cu 1 segment până când rămâne mai mică decât fereastra de primire. Dacă rețeaua nu este aglomerată, fereastra de încărcare va atinge treptat dimensiunea ferestrei de recepție. În condiții normale de redirecționare, dimensiunile acestor ferestre vor fi aceleași.

Rețineți că o pornire lent nu este atât de lent. După primul ACK, dimensiunea ferestrei de încărcare este de 2 segmente, iar după primirea cu succes a 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ă primim un ACK, apare o situație de timeout. Comportamentul ferestrei de încărcare în acest caz este discutat mai jos.

10.13.2 Sindromul ferestrei fără idee

În primele implementări TCP/IP, dezvoltatorii au întâlnit fenomenul sindromul „fereastră fără idee”.(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 de recepție citește 1 octet de date din tamponul de intrare (adică încet).

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

4. Aplicația care primește 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 de primire trimite un ACK care înseamnă „Mulțumesc. Am primit pachetul și nu mai am spațiu liber”.

7. Aplicația de primire 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ă ajungă datele și împinge constant informațiile primite în marginea stângă a ferestrei, efectuând o operațiune complet inutilă care generează trafic suplimentar în rețea.

Situațiile reale, desigur, nu sunt atât de extreme. Un expeditor rapid și un receptor lent vor schimba bucăți de date mici (față de dimensiunea maximă a segmentului) și vor comuta pe o fereastră de primire aproape plină. În fig. În figura 10.18 sunt prezentate condițiile de apariție a sindromului „fereastră prostească”.


Orez. 10.18. Fereastra de recepție a tamponului cu spațiu liber foarte mic

Rezolvarea acestei probleme nu este dificilă. De îndată ce fereastra de primire este redusă la o lungime mai mică decât această dimensiune țintă, TCP începe să înșele expeditorul. În această situație, TCP nu ar trebui să indice expeditorului adiţional spațiu de fereastră când aplicația care primește citește datele din buffer în bucăți mici. În schimb, trebuie să păstrați resursele eliberate secrete de la expeditor până când sunt suficiente. Se recomandă o singură dimensiune a segmentului, cu excepția cazului în care întregul buffer de intrare stochează un singur segment (în acest din urmă caz, se folosește o dimensiune de jumătate de tampon). Dimensiunea țintă pe care ar trebui să o raporteze TCP poate fi exprimată ca:

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

TCP începe să mintă 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ă din formulă. Rețineți că nu există niciun rău pentru expeditor, deoarece aplicația care primește oricum nu ar putea procesa multe dintre datele la care se așteaptă.

Soluția propusă poate fi ușor verificată în cazul discutat mai sus cu o ieșire ACK pentru fiecare dintre octeții recepționați. Aceeași metodă este potrivită și pentru cazul în care tamponul de intrare poate stoca mai multe segmente (cum este adesea cazul în practică). Expeditorul rapid va umple bufferul de intrare, dar receptorul va indica că nu are spațiu liber pentru a găzdui informațiile și nu va deschide această resursă până când dimensiunea ei nu va atinge întregul segment.

10.13.3 Algoritmul lui Nagle

Expeditorul trebuie, independent de destinatar, să evite trimiterea de segmente foarte scurte prin acumularea de date înainte de trimitere. Algoritmul lui Nagle implementează o idee foarte simplă care vă permite să reduceți numărul de datagrame scurte trimise prin rețea.

Algoritmul recomandă amânarea redirecționării datelor (și împingerii) în timp ce se așteaptă un ACK de la datele transmise anterior. Datele acumulate sunt trimise după primirea unui ACK pentru o informație trimisă anterior sau după primirea datelor pentru a le trimite în cantitatea unui segment complet sau la finalizarea unui timeout. 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 lățimea de bandă care poate fi utilizată pentru a redirecționa alt trafic. Dacă peer-ul TCP întârzie ușor trimiterea ACK-ului, atunci:

■ Mai multe segmente pot fi confirmate cu un singur ACK.

■ Aplicația care primește este capabilă să primească o anumită cantitate de date în intervalul de timeout, de ex. ACK-ul poate conține antetul de ieșire și nu necesită generarea unui mesaj separat.

Pentru a evita întârzierile la trimiterea unui flux de segmente de lungime completă (de exemplu, la schimbul de fișiere), ar trebui trimis un ACK pentru cel puțin fiecare alt segment complet.

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

10.13.5 Timeout retransmisie

După trimiterea segmentului, TCP setează un cronometru și monitorizează sosirea ACK-ului. Dacă un ACK nu este primit în perioada de expirare, TCP retransmite segmentul (releul). Cu toate acestea, care ar trebui să fie perioada de time-out?

Dacă este prea scurt, expeditorul va inunda rețeaua prin redirecționarea segmentelor inutile care dublează informațiile care au fost deja trimise. Un timeout prea mare va împiedica repararea rapidă a segmentelor care sunt efectiv distruse în timpul redirecționării, ceea ce va reduce debitul.

Cum să alegi perioada potrivită de timeout? O valoare care este potrivită pentru o rețea locală de mare viteză nu va fi potrivită pentru o conexiune la distanță cu multe accesări. Aceasta înseamnă că principiul „o valoare pentru orice condiții” este în mod clar nepotrivit. Mai mult, chiar și pentru o conexiune specifică existentă, condițiile rețelei 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 noile implementări. Le vom analiza pe scurt mai jos.

Bunul simț dictează că cea mai bună bază pentru estimarea timpului de expirare corect pentru o anumită conexiune ar fi monitorizarea durata ciclului(timp dus-întors) ca interval dintre trimiterea datelor și primirea confirmării primirii acestora.

Soluții bune pentru următoarele cantități pot fi obținute din statisticile de bază (vezi Figura 10.19) pentru a ajuta la calcularea timpului de expirare. Cu toate acestea, nu ar trebui să vă bazați pe medii, deoarece mai mult de jumătate dintre estimări vor fi mai mari decât media statistică. Luând în considerare câteva valori aberante, putem obține estimări mai bune care iau în considerare distribuția normală și reduc timpul de așteptare prea lung de retransmisie.


Orez. 10.19. Distribuția timpilor de ciclu

Nu este nevoie de o cantitate mare de calcule pentru a obține estimări matematice formale ale abaterilor. Puteți utiliza estimări destul de aproximative bazate pe valoarea absolută a diferenței dintre ultima valoare și estimarea medie:

Ultima abatere = | Ultimul ciclu - Medie |

Pentru a calcula valoarea corectă de timeout, un alt factor care trebuie luat în considerare este modificarea timpului ciclului din cauza condițiilor actuale ale rețelei. Ceea ce se întâmplă online în ultimul moment este mai important decât ceea ce s-a întâmplat acum o oră.

Să presupunem că calculăm media ciclului pentru o sesiune foarte lungă. Lăsați rețeaua să fie ușor încărcată la început și am identificat 1000 de valori mici, dar apoi 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 statistică de 170 de unități, dar apoi 50 de valori au fost măsurate cu o medie de 282, atunci media curentă ar fi:

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

O valoare mai rezonabilă ar fi timp de ciclu netezit(Smoothed Round-Trip Time - SRTT), care ia în considerare prioritatea valorilor ulterioare:

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

Valoarea lui α este între 0 și 1. Creșteți a are ca rezultat o influență mai mare a timpului curent al ciclului asupra mediei netezite. Deoarece calculatoarele pot efectua rapid împărțirea cu 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 curentă SRTT de 230 de unități atunci când o modificare a condițiilor rețelei determină creșterea progresivă a duratei ciclului (presupunând că nu are loc nicio expirare). Valorile din coloana 3 sunt folosite ca valori din coloana 1 pentru următorul rând al tabelului (adică, ca vechiul SRTT).


Tabelul 10.2 Calculul timpului de ciclu netezit

SRTT vechi 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 vine problema alegerii unei valori pentru timeout-ul de retransmisie. Analiza valorilor timpului de ciclu arată o abatere semnificativă a acestor valori de la valoarea medie curentă. Este logic să stabilim o limită pentru magnitudinea abaterilor. O valoare bună pentru timeout-ul de retransmisie (în standardele RFC această valoare se numește Retransmission TimeOut - RTO) este dată de următoarea formulă cu o constrângere de abatere netezită (SDEV):

T = Retransmission Timeout = SRTT + 2×SDEV

T = SRTT + 4×SDEV

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

DEV = | Timpul ultimului ciclu - SRTT vechi |

Formula de netezire este apoi utilizată pentru a lua în considerare această din urmă valoare:

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

Rămâne o întrebare - ce valori inițiale să luați? Recomandat:

Timeout inițial = 3s

SRTT inițial = 0

SDEV inițial = 1,5 s

Van Jacobson a definit un algoritm rapid care calculează foarte eficient timpul de expirare a retransmirii datelor.

10.13.6 Exemplu de statistici

Cât de reușit va avea timeout-ul calculat mai sus? Când această valoare a fost implementată, s-au observat îmbunătățiri semnificative ale performanței. Un exemplu ar fi statisticile echipei netstat, primit pe sistem tigrul- un server de Internet accesat de multe gazde din întreaga lume.


1510769 pachete (314955304 octeți) primite în secvență

Sistem tigrul 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% au fost duplicate. Trebuie avut în vedere faptul că nivelul pierderilor în datele de intrare corespunde aproximativ cu nivelul pentru segmentele de ieșire. Astfel, traficul de retransmisie risipitor reprezintă aproximativ 0,6% din traficul total.

10.13.7 Calcule după retrimitere

Formulele prezentate mai sus folosesc timpul de ciclu ca interval dintre trimiterea unui segment și primirea unei confirmări de primire a acestuia. Cu toate acestea, să presupunem că nu se primește nicio confirmare în perioada de expirare și datele trebuie retrimise.

Algoritmul lui Kern presupune că timpul ciclului nu ar trebui modificat în acest caz. Valoarea curentă a timpului de ciclu netezit și abatere netezităîși păstrează valorile până când se primește confirmarea de a redirecționa un anumit segment fără a-l retrimite. Din acest moment, calculele sunt reluate pe baza valorilor salvate și a noilor măsurători.

10.13.8 Acțiuni după retransmitere

Dar ce se întâmplă înainte de a primi confirmarea? După retransmisie, comportamentul TCP se schimbă radical, în principal din cauza pierderii de date din cauza congestionării rețelei. Prin urmare, răspunsul la retrimiterea datelor va fi:

■ Rată de retransmisie redusă

■ Combaterea congestionării rețelei prin reducerea traficului general

10.13.9 Frânare exponențială

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

Dacă defecțiunea rețelei continuă să apară, perioada de expirare se va dubla până când se atinge valoarea maximă prestabilită (de obicei 1 minut). După un timeout, un singur segment poate fi trimis. Un timeout apare și atunci când valoarea prestabilită pentru numărul de transferuri de date fără a primi un ACK este depășită.

10.13.10 Reducerea congestiei prin reducerea datelor trimise prin rețea

Reducerea cantității de date trimise este ceva mai complexă decât mecanismele discutate mai sus. Începe să funcționeze, la fel ca și startul lent deja menționat. Dar, deoarece este stabilită o limită pentru nivelul de trafic care poate duce inițial la probleme, viteza de schimb va încetini de fapt din cauza creșterii dimensiunii ferestrei de încărcare pentru un segment. Trebuie să setați valorile limită pentru a reduce efectiv viteza de trimitere. În primul rând, se calculează pragul de pericol:

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

Dacă valoarea rezultată este mai mare de două segmente, este folosită ca limită. În caz contrar, dimensiunea chenarului este setată la două segmente. Algoritmul de recuperare completă necesită:

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

■ Pentru fiecare ACK primit, măriți dimensiunea ferestrei de încărcare cu un segment până când este atinsă limita (la fel ca mecanismul de pornire lentă).

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

Scenariul ideal poate oferi o reprezentare simplificată a modului în care funcționează mecanismul 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 timeout-ul, iar limita a fost definită ca 4 segmente. Dacă aplicația de primire citește instantaneu date din buffer, dimensiunea ferestrei de primire va rămâne 8 segmente.

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

■ ACK primit - sunt trimise 2 segmente.

■ ACK primit pentru 2 segmente - sunt trimise 4 segmente (limita 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 primire).

Deoarece retransmiterea timeout necesită confirmarea primirii tuturor datelor trimise, procesul continuă până când fereastra de încărcare atinge dimensiunea ferestrei de primire. 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 crește liniar odată ce limita este atinsă.


Orez. 10.20. Limitarea vitezei de redirecționare în timpul aglomerației

10.13.11 ACK-uri duplicate

Unele implementări folosesc o caracteristică opțională numită retrimite rapid(retransmitere rapidă) - pentru a grăbi retrimiterea datelor în anumite condiții. Ideea sa de bază presupune ca destinatarul să trimită ACK-uri suplimentare care indică un gol în datele primite.

Atunci când primește un segment dezordonat, receptorul trimite înapoi un ACK care indică primul octet pierdut date (vezi Figura 10.21).


Orez. 10.21. ACK-uri duplicate

Expeditorul nu retransmite imediat datele deoarece IP-ul poate livra în mod normal date destinatarului fără o secvență de trimitere. Dar când sunt primite mai multe ACK-uri suplimentare de date duplicat (de exemplu, trei), segmentul lipsă va fi trimis fără a aștepta ca expirarea să se termine.

Rețineți că fiecare ACK duplicat indică primirea unui segment de date. Mai multe ACK-uri duplicate indică faptul că rețeaua este capabilă să furnizeze o cantitate suficientă de date și, prin urmare, nu este prea încărcată. Ca parte a algoritmului general, o mică reducere a dimensiunii ferestrei de încărcare este efectuată atunci când există o creștere reală a traficului de rețea. În acest caz, procesul de redimensionare radicală la restaurarea lucrărilor nu este aplicat.

Conform standardului Cerințe pentru gazdă(cerințe de gazdă) TCP trebuie să efectueze aceeași pornire lentă ca cea descrisă mai sus atunci când stinge sursa. Cu toate acestea, acest mesaj nu este vizat sau eficient deoarece conexiunea care primește mesajul poate să nu genereze foarte mult trafic. Specificația curentă Cerințe pentru router(cerințele routerului) indică faptul că routerele nu ar trebui trimite mesaje despre suprimarea sursei.

13/10/13 Statistici TCP

În sfârșit, să ne uităm la mesajele statistice ale echipei netstat, pentru a vedea multe dintre mecanismele descrise mai sus la lucru.

Segmentele se numesc pachete.
879137 pachete de date (226966295 octeți)
21815 pachete de date (8100927 octeți) retransmise
Re-expediere.
132957 pachete numai pentru confirmare (104216 întârziate)
Să notăm un număr mare

ACK întârziat.

Deschiderea ferestrei de sondare

dimensiune zero.

Acestea sunt mesaje SYN și FIN.
762469 conturi (pentru 226904227 octeți)
Semnal despre sosirea pachetelor

în afara secvenței.

1510769 pachete (314955304 octeți)
9006 pachete complet duplicate (867042 octeți)
Rezultat timeout cu real

livrarea datelor.

74 de pachete cu ceva dup. date (12193 octeți înșelat)
Pentru o mai mare eficienta

unele date au fost reambalate pentru a include octeți suplimentari la retrimitere.

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

incluse în mesajele sonore.

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

trimitere.

108 eliminat pentru sume de control necorespunzătoare
Sumă de control TCP nevalidă.
0 eliminat pentru câmpuri de decalaj de antet proaste
7 a fost aruncat deoarece pachetul este prea scurt
14677 conexiuni stabilite (inclusiv acceptări)
18929 conexiuni închise (inclusiv 643 drop)
4100 de conexiuni embrionare au scăzut
572187 segmente actualizate rtt (din 587397 încercări)
Încercări de modificare eșuate

timpul ciclului, deoarece ACK-ul nu a sosit înainte de expirarea timpului de expirare,

26 de conexiuni au fost întrerupte de expirarea rexmit-ului
Încercările ulterioare nereușite

retrimiteți, indicând o conexiune pierdută.

Timeout-uri de sondare

fereastră zero.

Timeout-uri de verificare

conexiune întreruptă.

472 de conexiuni eliminate de Keepalive

10.14 Conformitatea cu cerințele dezvoltatorului

Actualul standard TCP necesită ca implementările să adere strict la procedura de pornire lentă la inițializarea unei conexiuni și să utilizeze algoritmii Kern și Jacobson pentru estimarea timpului de retrimitere a datelor și controlul încărcării. Testele au arătat că aceste mecanisme conduc la îmbunătățiri semnificative ale performanței.

Ce se întâmplă când instalezi un sistem care nu respectă strict aceste standarde? Nu va oferi performanțe adecvate propriilor utilizatori și va fi un vecin sărac pentru alte sisteme din rețea, împiedicându-l să se recupereze de la o supraîncărcare temporară și să genereze trafic excesiv care duce la eliminarea datagramelor.

10.15 Bariere în calea productivității

TCP și-a dovedit flexibilitatea prin operarea prin rețele cu rate de transfer de sute sau milioane de biți pe secundă. Acest protocol a obținut rezultate bune în rețelele locale moderne cu topologii Ethernet, Token-Ring și Fibre Distributed Data Interface (FDDI), precum și pentru legăturile de comunicații de viteză redusă sau conexiunile la distanță lungă (similar cu legăturile prin satelit).

TCP este proiectat să răspundă la condiții extreme, cum ar fi congestionarea rețelei. Cu toate acestea, versiunea actuală a protocolului are caracteristici care limitează performanța în tehnologii promițătoare care oferă lățime de bandă de sute sau mii de megaocteți. Pentru a înțelege problemele implicate, 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ă efectuați un flux continuu de schimb cât mai eficient posibil. Să presupunem că:

■ Dimensiunea maximă a segmentului receptorului este de 1 KB.

■ Fereastra de primire - 4 KB.

Lățimea de bandă vă permite să trimiteți două segmente în 1 s.

■ Aplicația care primește consumă date pe măsură ce sosesc.

■ Mesajele ACK sosesc după 2 s.

Expeditorul este capabil să trimită date continuu. La urma urmei, când volumul alocat pentru fereastra este plin, sosește un ACK, care permite trimiterea unui alt segment:

După 2 s:

PRIMIȚI BILUL SEGMENTULUI 1, POATE TRIMITE SEGMENTUL 5.
PRIMIȚI BILUL SEGMENTULUI 2, POATE TRIMITE SEGMENTUL 6.
PRIMIȚI BILUL SEGMENTULUI 3, POATE TRIMITE SEGMENTUL 7.
PRIMIȚI BILUL SEGMENTULUI 4, POATE TRIMITE SEGMENTUL 8.

După alte 2 s:

PRIMIȚI BILUL SEGMENTULUI 5, POATE TRIMITE SEGMENTUL 9.

Dacă fereastra de primire era de numai 2 KB, expeditorul ar fi forțat 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 = Bandwidth×Cycle Time

Deși exemplul este oarecum exagerat (pentru a oferi numere mai simple), o fereastră mică poate cauza probleme la conexiunile prin satelit cu latență mare.

Acum să ne uităm la ce se întâmplă cu conexiunile de mare viteză. De exemplu, dacă lățimea de bandă și rata de redirecționare sunt măsurate la 10 milioane de biți pe secundă, dar timpul ciclului este de 100 ms (1/10 de 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 primire TCP este 65.536.

O altă problemă apare la viteze mari de transmisie, deoarece numerele de secvență se vor epuiza foarte repede. Dacă conexiunea poate transfera date la o viteză de 4 GB/s, atunci numerele de secvență trebuie actualizate în fiecare secundă. Nu va exista nicio modalitate de a face distincția între vechile datagrame duplicat care au fost întârziate cu mai mult de o secundă pe măsură ce s-au mutat pe Internet de la date noi proaspete.

Noi cercetări sunt efectuate în mod activ pentru a îmbunătăți TCP/IP și a elimina obstacolele menționate mai sus.

10.16 Funcții TCP

Acest capitol acoperă numeroasele funcții ale TCP. Principalele sunt enumerate mai jos:

■Asocierea porturilor cu conexiuni

■ Iniţializaţi conexiunile utilizând confirmarea în trei paşi

■ Efectuarea unei porniri lente pentru a evita supraîncărcarea rețelei

■ Segmentarea datelor în timpul transmisiei

■ Numerotarea datelor

■ Procesarea segmentelor duplicate primite

■ Calculul sumelor de control

■ Controlul fluxului de date prin fereastra de primire și fereastra de trimitere

■ Încetaţi conexiunea în modul stabilit

■ Încheierea conexiunii

■ Redirecționarea datelor urgente

■ Confirmarea pozitivă a reexpedierii

■ Calculaţi timpul de expirare a retransmisiei

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

■ Semnalizarea că segmentele sosesc defect

■ Sentirea închiderii ferestrei de primire

10.17 stări TCP

O conexiune TCP trece prin mai multe etape: conexiunea este stabilită prin schimbul de mesaje, apoi sunt trimise date, iar apoi conexiunea este închisă prin schimbul de mesaje speciale. Fiecare pas din operațiunea de conectare 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 ne vom uita pe scurt la tranziția tipică de stare între un server și un client situat la capetele opuse ale unei conexiuni. Nu ne propunem să oferim o descriere exhaustivă a tuturor stărilor posibile atunci când trimitem date. Este dat în RFC 793 și în document Cerințe pentru gazdă.

În timpul stabilirii conexiunii, serverul și clientul trec prin secvențe similare de stări. 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 Stare simulată înainte de a începe stabilirea conexiunii.
Deschidere pasivă de către o aplicație server.
ASCULTĂ (urmărire) Serverul așteaptă o conexiune de la client.
Serverul TCP primește SYN și trimite un SYN/ACK. Serverul a primit SYN și a trimis SYN/ACK. Merge să aștepte ACK.
SYN-PRIMIT Serverul TCP primește un ACK.
INSTALAT (instalat) ACK primit, conexiune deschisă.

Tabelul 10.4 Secvența stării clientului

Dacă partenerii ar încerca simultan să stabilească o conexiune între ei (ceea ce este extrem de rar), fiecare ar trece prin stările ÎNCHIS, SYN-TRIMIS, SYN-RECEIVED și STABILIT.

Părțile de sfârșit ale conexiunii rămân în starea STABILIT până când una dintre părți începe închidere conexiuni prin trimiterea segmentului FIN. În timpul unei închideri normale, partea care inițiază închiderea trece prin stările prezentate în Tabelul 10.5. Partenerul ei parcurge stările prezentate în Tabelul 10.6.


Tabelul 10.5 Secvența stărilor părții care închide legătura

Stări laterale de închidere Eveniment Descriere
STABILIT O aplicație locală solicită închiderea conexiunii.
TCP trimite FIN/ACK.
FIN-WAIT-1 Partidul de închidere așteaptă răspunsul partenerului. Permiteți-ne să vă reamintim că date noi pot ajunge în continuare de la partener.
TCP primește un ACK.
FIN-WAIT-2 Partea de închidere a primit un ACK de la peer, dar nu a primit încă un FIN. Partea de închidere așteaptă FIN când acceptă datele primite.
TCP primește FIN/ACK.
Trimite ACK.
TIMP DE AȘTEPTARE Conexiunea este menținută într-o stare nedeterminată pentru a permite sosirea sau eliminarea datelor duplicate sau a FIN-urilor duplicate existente încă în rețea. Perioada de așteptare este de două ori față de durata maximă estimată a segmentului.
ÎNCHIS

Tabelul 10.6 Secvența stărilor partenere la închiderea unei conexiuni

Statutul de partener Eveniment Descriere
STABILIT TCP primește FIN/ACK.
Așteptați aproape FIN a sosit.
TCP trimite un ACK.
TCP se 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-ul final.
TCP primește un ACK.
ÎNCHIS Toate informațiile de conectare au fost șterse.

10.17.1 Analizarea stărilor conexiunii TCP

Echipă netstat -an vă permite să verificați starea curentă a conexiunii. Conexiunile în state sunt prezentate mai jos asculta, pornire, stabilit, închidereȘi timp de așteptare.

Rețineți că numărul portului de conectare 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 cozile de ieșire.

Pro Recv-Q Send-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 INFIINTAT
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 INFIINTAT
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 INFIINTAT
Tcp 0 0 128.121.50.145.1082 128.121.50.141.6000 INFIINTAT
Tcp 0 0 128.121.50.145.1022 128.121.50.141.1017 INFIINTAT
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 INFIINTAT
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 INFIINTAT
Tcp 0 0 128.121.50.145.119 192.67.243.13.3704 INFIINTAT
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 INFIINTAT

10.18 Note despre implementări

De la bun început, protocolul TCP a fost conceput pentru a interopera echipamentele de rețea de la diferiți producători. Specificația TCP nu specifică exact cum ar trebui să funcționeze structurile interne de implementare. Aceste întrebări sunt lăsate în seama dezvoltatorilor, care au sarcina de a găsi cele mai bune mecanisme pentru fiecare implementare specifică.

Chiar și RFC 1122 (document Cerințe pentru gazdă - cerințe pentru gazde) lasă suficientă libertate pentru variații. 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. Drept urmare, utilizatorii se confruntă cu inconvenientul unei performanțe reduse.

Unele bune practici de implementare nu sunt incluse în standarde. De exemplu, securitatea poate fi îmbunătățită prin restricționarea utilizării porturilor binecunoscute prin procese privilegiate din sistem, dacă sistemul de operare local acceptă această metodă. Pentru a îmbunătăți performanța, implementările ar trebui să copieze și să mute datele trimise sau preluate cât mai puțin posibil.

Interfață standard de programare a aplicației nedefinit(precum și politica de securitate), astfel încât să existe spațiu liber pentru experimentarea cu diferite seturi de instrumente software. Cu toate acestea, acest lucru poate duce la utilizarea diferitelor interfețe de programare pe fiecare platformă și nu va permite mutarea software-ului aplicației între platforme.

De fapt, dezvoltatorii își bazează seturile de instrumente pe interfața de programare Socket, împrumutată de la Berkeley. Importanța interfeței software a crescut odată cu apariția WINSock (Windows Socket), care a dus la o proliferare de noi aplicații desktop care puteau rula peste orice interfață WINSock compatibilă cu stiva TCP/IP.

10.19 Lectură suplimentară

Standardul TCP original este definit în RFC 793. Actualizările, revizuirile și cerințele de compatibilitate sunt abordate în RFC 1122. Kern și Partridge au publicat articolul Îmbunătățirea estimărilor dus-întors în protocoale de transport fiabileÎn revistă Procesele 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 algoritmii de performanță.

Serverele care implementează aceste protocoale într-o rețea corporativă oferă clientului o adresă IP, gateway, 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 de auto-configurare numit AutoIP, care este un proiect al IETF Auto-Configuration Committee. Acest protocol este utilizat în rețelele mici pentru a atribui adrese IP locale de legătură gazdelor. Protocolul AutoIP determină independent adresa IP locală la legătura, folosind o schemă de negociere cu alte gazde și fără a contacta un server central.

Folosind protocolul PPPoE

Abrevierea PPPoE înseamnă Point-to-Point Protocol over Ethernet. Acest protocol încapsulează date pentru transmisie printr-o rețea Ethernet cu o topologie cu punte.

PPPoE este o specificație pentru conectarea utilizatorilor Ethernet la Internet printr-o conexiune în bandă largă, cum ar fi o linie digitală de abonat închiriată, un dispozitiv fără fir sau un modem prin cablu. Utilizarea protocolului PPPoE și a unui modem în bandă largă oferă utilizatorilor rețelelor locale de computere acces individual, autentificat la rețelele de date de mare viteză.

Protocolul PPPoE combină tehnologia Ethernet cu protocolul PPP, creând efectiv o conexiune separată la un server la distanță pentru fiecare utilizator. Controlul accesului, contabilitatea conexiunii și selectarea furnizorului de servicii sunt determinate pentru utilizatori, nu pentru gazde. Avantajul acestei abordări este că nici compania de telefonie, nici furnizorul de servicii de internet nu trebuie să ofere suport special pentru aceasta.

Spre deosebire de conexiunile dial-up, conexiunile DSL și modemurile prin cablu sunt întotdeauna active. Deoarece conexiunea fizică la un furnizor de servicii de la distanță este partajată între mai mulți utilizatori, este necesară o metodă de contabilitate care să înregistreze expeditorii și destinațiile traficului și să taxeze utilizatorii. Protocolul PPPoE permite utilizatorului și gazdei de la distanță care participă la o sesiune de comunicare să învețe reciproc adresele de rețea în timpul unui schimb inițial numit detectare(descoperire). Odată ce o sesiune a fost stabilită între un utilizator individual și o gazdă la distanță (de exemplu, un furnizor de servicii de Internet), sesiunea poate fi monitorizată în scopuri de acumulare. Multe case, hoteluri și corporații oferă acces public la Internet prin linii digitale de abonat folosind tehnologia Ethernet și protocolul PPPoE.

O conexiune prin protocolul PPPoE constă dintr-un client și un server. Clientul și serverul funcționează folosind orice interfață care este apropiată de specificațiile Ethernet. Această interfață este utilizată pentru a emite adrese IP clienților și pentru a asocia acele adrese IP cu utilizatorii și, opțional, cu stațiile de lucru, mai degrabă decât pentru autentificarea bazată pe stația de lucru. Serverul PPPoE creează o conexiune punct la punct pentru fiecare client.

Configurarea 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ă fugiio-pkt-*Cușofer potrivit. Exemplu: