Cum se configurează smartphone-uri și PC-uri. Portal informativ
  • Acasă
  • In contact cu
  • Aplicație tcp ip client server. Aplicație client-server pe un socket de flux TCP

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

TCP se integrează în mod natural în mediul client/server (vezi Figura 10.1). Aplicație server gandaci(ascultați) solicitările de conectare primite. De exemplu, serviciile WWW, de transfer de fișiere sau de acces la terminal ascultă cererile clienților. Comunicațiile în TCP sunt inițiate de subrutinele corespunzătoare care inițiază conexiunea la server (vezi Capitolul 21 despre API-ul socket).

Orez. 10.1. Clientul apelează serverul.

În realitate, clientul poate fi un alt server. De exemplu, serverele de e-mail se pot conecta cu 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? Cum transferă TCP datele către IP? Cum identifică protocoalele de transmitere și recepție TCP o conexiune de la aplicație la aplicație ș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 presupune că o aplicație trimite 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) mod de operare în care ambele două fluxuri date (vezi Figura 10.2).


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

10.2.2 Segmente

TCP poate converti fluxul de date de ieșire dintr-o aplicație într-un formular potrivit pentru plasarea în datagrame. Cum?

Aplicația trimite date către TCP, iar acest protocol le introduce tampon de ieșire(trimite buffer). Apoi, TCP taie bucăți de date din buffer și le trimite, adăugând un antet (în acest caz, segmente segment). Pe fig. 10.3 arată cum datele de la tampon de ieșire TCP-urile sunt pachetate în segmente. TCP transmite segmentul către IP pentru livrare ca o singură datagramă. Împachetarea 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 în bufferul 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 nu sunt adesea aplicabile 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 butonului î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 extrudare(Apăsaţi).

Dacă te uiți la operațiunile dintr-o sesiune interactivă, poți găsi multe fragmente cu puține date și, în plus, popping poate fi găsit în aproape fiecare fragment de date. Cu toate acestea, popping-ul nu trebuie 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 presupune un flux ordonat de octeți în drum spre 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 curând posibil.

Mecanism date urgente(date urgente) marchează informații speciale în segment ca urgent. Cu acest lucru, TCP îi spune egalului său că segmentul conține date urgente și poate indica unde se află. Partenerul trebuie să trimită 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. Ca și în cazul UDP, numerele de porturi TCP variază de la 0 la 65535. Porturile de la 0 la 1023 sunt cunoscute ca porturi 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 pe care le cunoaștem deja de la UDP. Rețineți că traficul de pe portul TCP 9 este complet izolat de traficul de pe portul UDP 9.


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

Port Aplicație Descriere
9 Aruncă Anulați toate datele primite
19 taxat Generator de caractere. Schimb de caractere
20 Date FTP Port de redirecționare FTP
21 FTP Port pentru dialog FTP
23 TELNET Port pentru autentificare de la distanță prin Telnet
25 SMTP Port protocol SMTP
110 POP3 Serviciul de eșantionare a corespondenței pe computer personal
119 NNTP Acces la știri online

Dar porturile folosite de clienți? În cazuri rare, clientul nu rulează pe un port binecunoscut. Dar în astfel de situații, dorind să deschidă o conexiune, de multe ori îi cere sistemului de operare să îi aloce un port neutilizat și nerezervat. La sfârșitul conexiunii, clientul trebuie să returneze acest port înapoi, după care portul poate fi reutilizat de un alt client. Deoarece există peste 63.000 de porturi TCP în pool-ul de numere nerezervate, limitele portului 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 adresa prizei. O conexiune TCP este complet identificată printr-o adresă de socket la fiecare capăt al acelei conexiuni. Pe fig. Figura 10.4 prezintă o conexiune între 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. În cele ce urmează, veți vedea 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 în același timp. Adresele unice de socket ale unui server sunt atribuite simultan tuturor clienților săi (vezi Figura 10.5).


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

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 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 datele în mod fiabil, păstrând în același timp ordinea de redirecționare ș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 considerat ca având un număr de serie. Antetul segmentului TCP conține un număr de secvență primul octet de date al acestui segment.

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

Receptorul datelor TCP efectuează o verificare strictă a numerelor de secvență de intrare pentru a verifica secvența în care au fost primite datele și că nu există părți pierdute. Deoarece ACK-ul poate fi pierdut sau întârziat aleatoriu, segmentele duplicat pot ajunge la receptor. Numerele de secvență vă permit să determinați duplicarea datelor, care sunt apoi eliminate.

Pe 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 încorporate ș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 care urmează să fie redirecționat.


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

Un mic detaliu trebuie remarcat. 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 trimițând un antet fără date atașate. Desigur, valoarea ACK este prezentă în acest antet. În câmpul de secvență - valoarea 51, adică. următorul număr de octeți intenționează trimite TCP. Când TCP trimite următoarele date, noul antet TCP va avea, de asemenea, valoarea 51 în câmpul de secvență.

10.4 Stabilirea unei conexiuni

Cum sunt conectate cele două aplicații? Înainte de comunicare, fiecare dintre ei apelează la o rutină pentru a forma un bloc de memorie care va fi folosit pentru a stoca parametrii TCP și IP ai acestei conexiuni, cum ar fi adresele de socket, numărul de secvență curent, valoarea inițială a duratei de viață și așa mai departe.

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

Există o caracteristică tehnică. Fiecare parte începe să numeroteze fiecare octet nu de la unul, ci de la număr de serie aleatoriu(Vom vedea de ce se face acest lucru mai târziu.) Specificația originală recomandă generarea numărului 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 Scenariul conexiunii

Procedura de conectare este adesea denumită 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 unei conexiuni, partenerii fac schimb de 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 de secvență inițial utilizat pentru datele de ieșire

Rețineți că fiecare parte folosește operațiunile 1 și 2 pentru a indica limitele la care va acționa cealaltă parte. Un computer personal poate avea un buffer de primire mic, în timp ce un supercomputer poate avea un tampon uriaș. Structura de memorie a unui computer personal poate limita porțiunile de date primite la 1 KB, iar supercomputerul este controlat cu segmente mari.

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

Pe fig. Figura 10.8 prezintă un exemplu de script de conexiune. Sunt furnizate numere de succesiune de pornire foarte simple pentru a nu supraîncărca cifra. 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 cu clienții (această stare se numește deschis pasiv - deschis pasiv).

2. Clientul cere 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). În acest segment, sunt trimise 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ță inițial (3000), ACK 1001 (ceea ce înseamnă numerotarea primului octet trimis de client ca 1001), dimensiunea ferestrei de primire (4K) și dimensiunea celui mai mare segment pe care îl poate primi serverul (1024 octeți).

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

6. Client TCP spune aplicației sale să deschidă o conexiune.

7. Serverul TCP, după ce a primit un mesaj ACK de la clientul TCP, informează aplicația sa că conexiunea a fost deschisă.

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 unul foarte bun) în care aplicațiile peer se deschid în mod activ reciproc în același timp.

10.4.2 Setarea valorilor parametrilor IP

Solicitarea unei aplicații de a stabili o conexiune poate specifica și parametrii pentru datagramele IP care vor transporta datele conexiunii. Dacă nu este specificată o valoare specifică a parametrului, se utilizează valoarea implicită.

De exemplu, o aplicație poate alege 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 aplicate pentru fiecare direcție de schimb.

Când o aplicație utilizează opțiuni de securitate guvernamentală sau militară, fiecare punct final de conectare trebuie să folosească aceleași niveluri de securitate, altfel conexiunea va eșua.

10.5 Redirecționarea datelor

Transferul de date începe după finalizarea confirmării de creare a conexiunii în trei pași (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. 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 trebuie 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 această ordine. Rețineți că clientul nu așteaptă un ACK după fiecare segment trimis. Datele sunt trimise către peer până când spațiul său tampon este plin (vom vedea mai jos că receptorul poate specifica foarte precis cantitatea de date care trebuie trimisă către acesta).

Serverul salvează lățimea de bandă a conexiunii utilizând un singur ACK pentru a indica faptul că toate segmentele au fost redirecționate cu succes.

Pe fig. Figura 10.10 arată redirecționarea datelor 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 ACK confirmând 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 în următorul scenariu:

A:

B:"Bun".

LA:„Am terminat și eu treaba”.

A:"Bun".

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

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

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

LA:„Am terminat și eu treaba”.

A:"Bun".

În exemplul de mai jos, conexiunea închide serverul, așa cum este adesea cazul pentru comunicațiile client/server. În acest caz, după ce utilizatorul intră în sesiune telnet comanda de deconectare (deconectare din sistem) serverul inițiază 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 (FIN), informându-și peer-ul că nu mai sunt date de trimis.

3. Clientul TCP 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 își informează TCP-ul că conexiunea este închisă.

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 dintre egali trimite un mesaj ACK.

10.6.1 Încetarea bruscă

Oricare dintre părți poate solicita întreruperea 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ă serioasă de comunicare pe care nu o poate rezolva de la sine. O terminare bruscă este solicitată prin trimiterea unuia sau mai multor mesaje de resetare către peer, așa cum este indicat de un indicator specific din 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ă restricție afectează expeditorul TCP. Următoarea explicație a acestui mecanism este conceptuală, iar dezvoltatorii o pot implementa diferit î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 acest lucru. De obicei, dimensiunea tamponului este exprimată ca un număr întreg de dimensiuni maxime ale segmentelor.

Fluxul de date intră în buffer-ul de intrare și este stocat acolo până când este transmis către aplicație (determinat de portul TCP). Pe fig. Figura 10-12 prezintă un buffer de intrare care poate lua 4 KB.


Orez. 10.12. Fereastra de primire a tamponului de intrare

Spațiul tampon se umple pe măsură ce sosesc datele. Când aplicația de primire extrage 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 încărcat un fișier pe 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, un alt program poate începe (de exemplu, conform unui program) și până când programul FTP pornește din nou, următoarele date vor fi deja în buffer.

Fereastra de recepție este extinsă de la ultimul octet confirmat până la sfârșitul buffer-ului. Pe fig. 10.12, întregul buffer este mai întâi disponibil și, prin urmare, este disponibilă o fereastră de primire 4K. 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 1K va reduce fereastra de recepție la 1K.

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 momentul pornirii conexiunii, deși standardul TCP nu specifică modul de gestionare a acestui buffer. Bufferul 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 acesta ajunge nefuncțional? În general, se consideră că toate implementările stochează datele primite în fereastra de primire și trimit o confirmare (ACK) doar pentru un întreg bloc contiguu de mai multe segmente. Acesta este modul corect, deoarece, în caz contrar, eliminarea datelor nerespectate va degrada semnificativ performanța.

10.7.2 Fereastra de trimitere

Un sistem 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 receptorului. Activ spatiu de trimitere(spațiu de trimitere) Se extinde de la primul octet neconfirmat la stânga 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 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 de 4 KB.

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

3. Sosește un 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ă, sosește un ACK pentru toate datele transmise (adică toate primite de către receptor). ACK restabilește dimensiunea ferestrei de trimitere la 4 KB.

Orez. 10.13. Fereastră de trimitere

Trebuie subliniate câteva caracteristici interesante:

■ Expeditorul nu așteaptă un ACK pentru fiecare dintre segmentele de date pe care le trimite. Singura limitare a transferului este dimensiunea ferestrei de primire (de exemplu, expeditorul trebuie să transfere doar segmente de un 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

Pe 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 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 primită și procesată de sistem. Totuși, titlul 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 MSS declarată + 40 - (suma lungimilor antetului TCP și IP)

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

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

MSS impune o limită strictă a datelor trimise către TCP: receptorul nu va putea procesa valori mari. Cu toate acestea, expeditorul folosește segmente dimensiune mai mică 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 singura un segment care are un câmp ACK de 0. Rețineți că securitatea utilizează această caracteristică pentru a detecta cererile primite pentru o sesiune TCP.

Camp număr de serie conţine numărul de ordine de început(număr de ordine inițial), câmp fereastră - dimensiunea initiala fereastra de recepție. Singura setare 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 se presupune că o primește TCP. Această valoare are 32 de biți și este de obicei prezentă în cererea de conectare în câmp Opțiuni(Opțiune). Lungimea antetului TCP care conține valoarea MSS este de 24 de octeți.

10.8.3 Utilizarea câmpurilor de antet într-un răspuns de conexiune

Într-un răspuns de permis la o solicitare de conexiune, ambele steaguri (SYN și ACK) sunt setate la 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 de conexiune (î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 steag de resetare (RST) cu o valoare de 1 în răspuns.

10.8.4 Selectarea unui număr de ordine de început

Specificația TCP presupune că în timpul stabilirii unei conexiuni, fiecare parte alege numărul de ordine de început(pe baza valorii curente a temporizatorului intern pe 32 de biți). Cum se face?

Imaginează-ți ce se întâmplă când sistemul se blochează. 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 care rulează deja ș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 de la sfârșitul conexiunii poate să nu fie conștientă de faptul că partenerul său a suferit un accident și a fost apoi restabilit. Toate acestea vor duce la întreruperi serioase, mai ales când durează mult timp până când datele vechi trec prin rețea și se amestecă 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ă o adresă 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 cea mai bună modalitate de a selecta numerele de bază securizate.

10.8.5 Utilizarea comună 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 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ă(Fereastră) 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 pot fi acceptați. Rețineți că această valoare permite controlul precis al fluxului de date. Cu această valoare, peer-ul indică starea reală a ferestrei de recepție în timpul sesiunii de schimb.

Dacă o aplicație indică o operațiune TCP push, atunci indicatorul PUSH este setat la 1. TCP-ul care primește 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, dacă este setat la 1, implică un transfer de date urgent, iar pointerul corespunzător trebuie să indice ultimul octet al datelor urgente. O utilizare tipică a datelor urgente este de a trimite semnale de la terminal pentru a anula sau anula.

Datele urgente sunt adesea numite informații în afara benzii(în afara benzii). Cu toate acestea, acest termen este inexact. Datele urgente sunt trimise pe un flux TCP normal, deși implementările individuale pot avea mecanisme speciale pentru a indica unei aplicații că au sosit date urgente, iar aplicația trebuie să examineze conținutul datelor urgente înainte de a sosi toți octeții de mesaj.

Indicatorul RESET este setat la 1 atunci când o conexiune ar trebui să fie întreruptă. Același flag este setat în răspuns atunci când este primit 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 control IP este doar pentru antetul IP, în timp ce suma de control TCP este calculată pentru întregul segment, precum și pentru pseudo-antetul generat din antetul IP. În timpul calculului sumei de control TCP, câmpul corespunzător este setat la 0. În fig. Figura 10-15 prezintă un pseudo antet foarte asemănător cu cel utilizat în suma de control UDP.


Orez. 10.15. Câmp pseudo-antet 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 în UDP. Suma de control a segmentului de intrare este mai întâi calculată de către receptor și apoi comparată cu conținutul câmpului sumă de control al antetului TCP. Dacă valorile nu se potrivesc, segmentul este eliminat.

10.9 Exemplu de segment TCP

Orez. 10.16, protocolul analizorului Mirositoare de 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 Sniffer Parser

Analizor Mirositoare traduce majoritatea valorilor în zecimală. Cu toate acestea, valorile steagului sunt afișate ca hexazecimal. Indicatorul cu valoarea 12 este 010010. Suma de control este, de asemenea, scoasă în format hexazecimal.

10.10 Suport pentru operarea sesiunii

10.10.1 Sondarea ferestrei

Un expeditor rapid și un receptor lent pot forma o fereastră de primire de 0 octeți. Acest rezultat se numește închiderea ferestrei(fereastră închisă). Când există spațiu liber pentru a actualiza dimensiunea ferestrei de primire, se utilizează 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 economisiți cronometrul(temporizator persistent) la închiderea unei ferestre premium. Valoarea temporizatorului este timeout-ul de retransmisie. La sfârșitul cronometrului, un segment este trimis partenerului fereastra de detectare(sonda fereastră; unele implementări includ date). Sonda determină peer-ul să trimită înapoi un ACK care raportează starea curentă a ferestrei.

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

10.11 Încheierea unei sesiuni

10.11.1 Timeout

Partenerul de conexiune se poate prăbuși sau poate fi complet întrerupt din cauza unei erori de gateway sau de legătură. Pentru a preveni retransmiterea datelor în TCP, există mai multe mecanisme.

La atingerea primului prag de retransmisie (releu), TCP îi spune IP să verifice ruterul eșuat și, în același timp, informează aplicația despre problemă. TCP continuă să trimită date până când este atinsă a doua valoare limită și abia apoi închide conexiunea.

Desigur, înainte să se întâmple acest lucru, este posibil să existe un mesaj ICMP care să indice 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ă destinația este inaccesibilă.

O aplicație își poate seta propriul timeout de livrare a datelor și își poate efectua propriile operațiuni atunci când acest interval expiră. De obicei, conexiunea este întreruptă.

10.11.2 Menținerea unei conexiuni

Când o conexiune neterminată are date de trimis pentru o perioadă lungă de timp, aceasta devine inactiv. În timpul unei perioade de inactivitate, poate apărea o blocare a rețelei sau o eroare a conexiunii 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 îndeplinit 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 unei conexiuni(menține în viață) care testează conexiunile inactive. Astfel de mesaje sunt trimise periodic partenerului pentru a verifica existența acestuia în rețea. Răspunsul trebuie să fie mesaje ACK. Utilizarea mesajelor de menținere în viață este opțională. Dacă sistemul are această capacitate, aplicația o poate suprascrie prin propriile mijloace. Perioada estimată Mod implicit pentru întreținerea conexiunii timeout este de două ore!

Amintiți-vă că aplicația își poate seta propriul cronometru, conform căruia, la nivelul său, va decide întreruperea conexiunii.

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 întârzierile în rețeaua fizică în utilizare limitează sever debitul. Calitatea slabă a transferului de date are ca rezultat un volum mare de datagrame aruncate, ceea ce provoacă retransmisii și, în consecință, reduce eficiența lățimii de bandă.

Partea de recepție trebuie să ofere suficient spațiu tampon pentru a permite expeditorului să transfere date fără pauze în funcționare. Acest lucru este deosebit de important pentru rețelele cu latență mare, unde există o perioadă lungă de timp între trimiterea datelor și primirea ACK-urilor (și, de asemenea, atunci când se negociază dimensiunea ferestrei). Pentru a menține un flux constant de date de la sursă, partea de recepție trebuie să aibă o fereastră nu mai mică decât produsul lățimii de bandă și întârziere.

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 fereastra de recepție de pe cealaltă parte trebuie să aibă o dimensiune de cel puțin 20.000 de octeți, altfel fluxul de date va fi să nu fie 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 o operație și treceți la alta. 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ă serviți toate aceste operațiuni, ascunzând încărcarea sistemului. Implementările care integrează TCP/IP cu nucleul sistemului de operare pot reduce semnificativ încărcarea 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 un administrator de rețea să le poată personaliza pentru a se potrivi cerințelor locale. De exemplu, capacitatea de a ajusta dimensiunea bufferului pentru lățimea de bandă și latența rețelei va îmbunătăți considerabil performanța. Din păcate, multe implementări nu acordă suficientă atenție acestei probleme și codifică parametrii de comunicare.

Să presupunem că mediul de rețea este perfect: există resurse suficiente și schimbarea contextului este mai rapidă decât cowboy-ii își scot armele. 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 cel care respectă RFC 1122, care definește cerințele pentru nivelul de comunicare al gazdelor Internet.

O excepție la fel de importantă ș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 date mici și au temporizatoare î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 la o introducere în partea destul de complexă a TCP, ne vom uita la mecanismele de îmbunătățire a performanței și de a face față degradărilor debitului. Această secțiune discută următoarele probleme:

pornire lent(pornire lentă) împiedică utilizarea unei cantități mari de trafic de rețea pentru o nouă sesiune, ceea ce poate duce la supraîncărcare.

■ Vindecarea de Sindromul ferestrei fără idee(sindromul ferestrei prostești) împiedică aplicațiile prost proiectate să inunde rețeaua cu mesaje.

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

Timeout de retransmisie calculat(Timeout de retransmisie de calcul) se bazează pe negocierea sesiunii în timp real, reducând retransmisiile inutile, fără a provoca întârzieri mari pentru schimburile de date necesare efectiv.

■ Redirecționarea TCP se blochează când suprasarciniîn rețea permite routerelor să revină la modul original și să partajeze resursele de rețea pentru toate sesiunile.

■ Livrare ACK-uri duplicat(duplicat ACK) la primirea unui segment din secvență, permite colegilor să retransmită înainte de expirarea timpului.

10.13.1 Pornire lentă

Dacă toate aparatele electrocasnice sunt pornite în același timp acasă, 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ă noua conexiune pornește cu succes cu o creștere lentă a ratei de transfer de date în conformitate cu sarcina 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, atâta timp cât 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. Într-o stare normală de redirecționare, aceste ferestre vor avea aceeași dimensiune.

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ă un ACK reușit 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, a apărut 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 ale TCP/IP, dezvoltatorii au întâlnit acest fenomen Sindromul ferestrei fără idee(Silly Window Syndrome - SWS), care s-a manifestat destul de des. Pentru a înțelege ce se întâmplă, 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 transmitere 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 emițător rapid și un receptor lent vor schimba bucăți mici (în raport cu dimensiunea maximă a segmentului) de date și vor comuta pe o fereastră de primire aproape completă. Pe fig. 10.18 arată condițiile de apariție a sindromului „fereastră prostească”.


Orez. 10.18. Primiți tampon de fereastră cu spațiu liber foarte mic

Rezolvarea acestei probleme este ușoară. De îndată ce fereastra de primire este redusă cu o lungime mai mică decât dimensiunea țintă dată, TCP începe să înșele expeditorul. În această situație, TCP nu trebuie să direcționeze expeditorul adiţional spațiu în fereastră când aplicația care primește citește datele din buffer în bucăți mici. În schimb, eliberarea resurselor ar trebui să fie păstrată secretă 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 utilizează o dimensiune egală cu jumătate din buffer). 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ă trișeze atunci când dimensiunea ferestrei este mai mică decât această dimensiune și va spune adevărul atunci când dimensiunea ferestrei nu este mai mică decât valoarea dată de formulă. Rețineți că nu există niciun rău pentru expeditor, deoarece aplicația care primește încă nu ar putea procesa o mare parte din datele la care se așteaptă.

Soluția propusă este ușor de verificat în cazul discutat mai sus cu ieșirea 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 (cum se întâmplă adesea în practică). Expeditorul rapid va umple bufferul de intrare, dar receptorul va indica că nu are spațiu liber pentru a stoca informații ș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, indiferent de destinatar, sa evite trimiterea de segmente foarte scurte prin acumularea de date inainte de a trimite. Algoritmul lui Nagle implementează o idee foarte simplă de a reduce numărul de datagrame scurte trimise prin rețea.

Algoritmul recomandă amânarea transferului de date (și popping) în timp ce se așteaptă un ACK de la datele transmise anterior. Datele acumulate sunt trimise după primirea unui ACK către o informație trimisă anterior sau după primirea pentru a trimite date de dimensiunea 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 modul în care ACK este întârziat. Reducerea numărului de ACK-uri reduce cantitatea de lățime de bandă care poate fi utilizată pentru a trimite alt trafic. Dacă partenerul TCP întârzie ușor trimiterea ACK, 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. antetul de ieșire poate fi inclus în ACK și nu trebuie generat niciun mesaj separat.

Pentru a evita întârzierile la redirecționarea unui flux de segmente de lungime completă (de exemplu, la schimbul de fișiere), ar trebui trimis un ACK pentru cel puțin fiecare al doilea segment de lungime 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 buffer-ul de intrare pentru a primi date noi, iar expeditorul poate continua transferul (în plus, retransmisia este de obicei mult mai lentă). Dacă ajunge un întreg segment, trebuie să răspundeți la el cu un mesaj ACK în aceeași secundă.

10.13.5 Timeout retransmisie

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

Dacă este prea scurt, expeditorul va inunda rețeaua cu segmente inutile care dublează informațiile deja trimise. Un timeout prea lung va împiedica repararea rapidă a segmentelor care sunt de fapt corupte în timpul transferului, ceea ce va reduce debitul.

Cum să alegi intervalul corect pentru timeout? O valoare care este potrivită pentru o rețea LAN de mare viteză nu va fi potrivită pentru o conexiune la distanță cu multe accesări. Prin urmare, principiul „o valoare pentru orice condiții” este în mod clar nepotrivit. În plus, chiar și pentru o conexiune specifică existentă, condițiile rețelei se pot schimba, iar întârzierile pot crește sau scădea.

Algoritmii lui 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 revizui pe scurt mai jos.

Bunul simț dictează că cea mai bună bază pentru estimarea timpului de expirare corect pentru o anumită conexiune ar putea fi urmărirea 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 pe baza statisticilor elementare (vezi Figura 10.19) care vor ajuta la calcularea timpului de expirare. Cu toate acestea, nu vă bazați pe medii, deoarece mai mult de jumătate din scoruri vor fi mai mari decât media statistică. Luând în considerare o pereche de variații, pot fi obținute estimări mai bune care țin cont de distribuția normală și reduc latența de retransmisie prea lungă.


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 de luat în considerare este modificarea timpului ciclului din cauza condițiilor actuale ale rețelei. Ceea ce s-a întâmplat online în ultimul moment este mai important decât ceea ce s-a întâmplat acum o oră.

Să presupunem că calculați media ciclului pentru o sesiune foarte lungă. Să presupunem că la început rețeaua a fost ușor încărcată și am determinat 1000 de valori mici, dar apoi a existat o creștere a traficului cu o creștere semnificativă a timpului de întârziere.

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

170x1000/1050 + 282x50/1050 = 175

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) + α×Valoare 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 computerele pot împărți rapid la puterile lui 2 prin deplasarea numerelor binare la dreapta, valoarea pentru α este întotdeauna (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 are ca rezultat o creștere secvențială a duratei ciclului (presupunând că nu are loc un timeout). Valorile din coloana 3 sunt folosite ca valori din coloana 1 pentru următorul rând din tabel (adică vechiul SRTT).


Tabelul 10.2 Calcularea 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 se pune problema alegerii unei valori pentru timeout-ul de retransmisie. O analiză a timpilor ciclului arată o abatere semnificativă a acestor valori de la media curentă. Este logic să stabilim o limită pentru mărimea abaterilor (abaterilor). Valorile bune pentru timeout-ul de retransmisie (numit Retransmission TimeOut - RTO în standardele RFC) sunt date de următoarea formulă cu o varianță netezită constrânsă (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 |

Apoi se folosește o formulă de netezire pentru a contabiliza ultima 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 = 3 s

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 retransmisiei.

10.13.6 Exemplu de statistici

Cât de bine va funcționa timeout-ul calculat mai sus? La implementarea valorii obținute s-au observat îmbunătățiri semnificative ale performanței. Un exemplu ar fi statisticile de comandă netstat primite pe sistem tigru- un server de Internet care este accesat de multe gazde din întreaga lume.


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

sistem tigru 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 fiind ACK-uri pure), doar 0,6% au fost duplicate. În acest caz, trebuie luat în considerare faptul că nivelul pierderilor în datele de intrare corespunde aproximativ cu nivelul pentru segmentele de ieșire. Astfel, traficul de retransmisie inutil reprezintă aproximativ 0,6% din traficul total.

10.13.7 Calcule după retrimitere

Formulele de mai sus folosesc valoarea timpului 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 timpul perioadei de expirare și că datele trebuie retrimise.

Algoritmul lui Kern presupune că în acest caz timpul ciclului nu ar trebui modificat. Valoarea actuală netezită a timpului ciclului și abatere netezităîși păstrează valorile până când se primește o confirmare pentru a trimite un segment fără a-l retrimite. Din acest moment, calculele sunt reluate pe baza valorilor stocate și a noilor măsurători.

10.13.8 Acțiuni după retransmitere

Dar ce se întâmplă înainte de a primi confirmarea? După o retransmisie, comportamentul TCP se schimbă drastic, î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ă

■ Combateți congestionarea rețelei prin reducerea traficului general

10.13.9 Frânare exponențială

După o retransmisie, intervalul de timeout este dublat. Totuși, ce se întâmplă când temporizatorul se depășește din nou? Datele vor fi trimise din nou și 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 atinge o valoare maximă prestabilită (de obicei 1 minut). După expirarea timpului, un singur segment poate fi trimis. 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 aglomerației prin reducerea datelor trimise prin rețea

Reducerea cantității de date trimise este ceva mai complicată decât mecanismele discutate mai sus. Începe să funcționeze, ca și startul lent deja menționat. Dar, deoarece este stabilită o limită pentru nivelul de trafic, care poate duce inițial la probleme, cursul de schimb va încetini de fapt din cauza creșterii dimensiunii ferestrei de încărcare pentru un segment. Trebuie să setați valorile de frontieră pentru o reducere reală a vitezei 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 complet de recuperare necesită:

■ Setați dimensiunea ferestrei de încărcare la un 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 aleasă pe baza ratei de creștere într-un segment pentru timpul ciclului (creșterea este calculată ca MSS/N, unde N este dimensiunea fereastra de încărcare pe segmente).

Scenariul pentru cazul ideal poate fi o reprezentare simplistă a modului în care funcționează mecanismul de recuperare. Să presupunem că fereastra de primire a peer-ului (și fereastra de încărcare curentă) a fost de 8 segmente înainte de a fi detectat timeout-ul, iar limita este definită a fi 4 segmente. Dacă aplicația de recepție citește instantaneu date din buffer, dimensiunea ferestrei de primire va rămâne la 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ă).

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

■ A primit ACK 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 toate datele trimise trebuie confirmate în timpul expirării retransmisiei, 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ă, iar odată ce limita este atinsă, creșterea este liniară.


Orez. 10.20. Limită de rată înainte în timpul aglomerației

10.13.11 ACK-uri duplicate

În unele implementări, este utilizată o caracteristică opțională - așa-numita reexpediere rapidă(retransmitere rapidă) - pentru a accelera retransmiterea datelor în anumite condiții. Ideea sa principală este legată de faptul că destinatarul trimite ACK-uri suplimentare care indică un gol în datele primite.

La primirea unui segment necomandat, receptorul trimite înapoi un ACK care indică primul octet. pierdut date (vezi Figura 10.21).


Orez. 10.21. ACK-uri duplicate

Expeditorul nu realizează retransmiterea instantanee a datelor deoarece IP-ul poate livra în mod normal date destinatarului fără o secvență de trimitere. Dar când se primesc mai multe ACK-uri suplimentare pentru duplicarea datelor (de exemplu, trei), atunci 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. Câteva ACK-uri duplicat arată clar că rețeaua este capabilă să furnizeze suficiente date și, prin urmare, nu este încărcată prea mult. 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 drastică la refacerea lucrării nu se aplică.

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 stingerea sursei. Totuși, raportarea acestui lucru nu este țintită sau eficientă, deoarece conexiunea care a primit mesajul poate să nu genereze prea mult trafic. Specificația curentă Cerințe pentru router(cerințe de router) specifică că routerele nu ar trebui trimite mesaje de suprimare a sursei.

10.13.13 Statistici TCP

În cele din urmă, să aruncăm o privire la mesajele statistice ale comenzii netstat, pentru a vedea multe dintre mecanismele descrise mai sus în acțiune.

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)
Observați numărul mare

ACK-uri întârziate.

Se aude deschiderea ferestrei

dimensiunea zero.

Acestea sunt mesaje SYN și FIN.
762469 conturi (pentru 226904227 octeți)
Semnal de sosire pachet

în afara secvenței.

1510769 pachete (314955304 octeți)
9006 pachete complet duplicate (867042 octeți)
Rezultatul unui timeout cu un real

livrarea datelor.

74 de pachete cu ceva dup. date (12193 octeți înșelat)
Pentru a fi mai eficient

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 nereușite de schimbare

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.

Verificați timeout-urile

conexiune inactivă.

472 de conexiuni eliminate de Keepalive

10.14 Conformitatea cu cerințele dezvoltatorului

Standardul actual 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 a estima timpul de expirare a retrimiterii și a controla încărcarea. 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 prost pentru alte sisteme din rețea, prevenind restabilirea funcționării normale după o supraîncărcare temporară și generând trafic excesiv care duce la pierderea datagramelor.

10.15 Bariere în calea performanței

TCP și-a dovedit flexibilitatea prin operarea în rețele cu rate baud 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ături de viteză redusă sau conexiuni la distanță lungă (cum ar fi 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 tehnologiile emergente care oferă sute și mii de megaocteți de lățime de bandă. 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 de destinaţie este de 1 KB.

■ Fereastra de primire - 4 KB.

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

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

■ Mesajele ACK sosesc după 2 secunde.

Expeditorul este capabil să trimită date continuu. La urma urmei, când volumul alocat ferestrei este plin, sosește un ACK, permițând 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ă încă 2 secunde:

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

Dacă fereastra de primire a fost de numai 2K, 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 = Bandwidth×Cycle Time

Deși exemplul este oarecum exagerat (pentru a oferi numere mai simple), o fereastră mică poate duce la probleme cu 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 transfer sunt măsurate la 10 Mbps, 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 epuizează foarte repede. Dacă conexiunea poate trimite date la o rată de 4 GB / s, atunci numerele de secvență ar trebui actualizate în fiecare secundă. Nu va exista nicio modalitate de a face distincția între vechile datagrame duplicate care au fost întârziate cu mai mult de o secundă pe măsură ce au călătorit pe Internet și date noi și proaspete.

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

10.16 Funcții TCP

Acest capitol acoperă numeroasele caracteristici ale TCP. Principalele sunt enumerate mai jos:

■ Asocierea porturilor cu conexiuni

■ Inițializarea conexiunilor prin confirmare în trei pași

■ Efectuarea unei porniri lente pentru a evita congestionarea rețelei

■ Segmentarea datelor în tranzit

■ Numerotarea datelor

■ Gestionarea segmentelor duplicat primite

■ Calculul sumei de control

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

■ Încheierea conexiunii în modul prescris

■ Încheierea conexiunii

■ Redirecționarea datelor urgente

■ Confirmare de retrimitere pozitivă

■ Calcul de expirare a retransmisiei

■ Reducerea traficului invers în timpul congestionării rețelei

■ Semnalizarea segmentelor necomandate

■ Verificarea închiderii ferestrei de primire

10.17 stări TCP

O conexiune TCP trece prin mai multe etape: o conexiune este stabilită printr-un schimb de mesaje, apoi sunt trimise date, iar apoi conexiunea este închisă folosind un schimb de mesaje speciale. Fiecare pas în operarea 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 lua în considerare pe scurt o schimbare tipică a stării unui server și a unui client situat la diferite capete ale conexiunii. Nu ne propunem să oferim o descriere exhaustivă a tuturor stărilor posibile la transferul datelor. Este dat în RFC 793 și document Cerințe pentru gazdă.

În timpul stabilirii conexiunilor, 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

Stare server Eveniment Descriere
ÎNCHIS Starea falsă înainte de a începe configurarea conexiunii.
Deschidere pasivă prin aplicație server.
ASCULTĂ (urmărire) Serverul așteaptă o conexiune de la client.
Serverul TCP primește SYN și trimite SYN/ACK. Serverul a primit un SYN și a trimis un SYN/ACK. Merge la așteptarea ACK.
SYN PRIMIT Serverul TCP primește un ACK.
INSTALAT (instalat) ACK primit, conexiune deschisă.

Tabelul 10.4 Secvența stării clientului

Dacă colegii ar încerca să stabilească o conexiune între ei în același timp (ceea ce este extrem de rar), fiecare ar trece prin stările ÎNCHIS, SYN-SENT, SYN-RECEIVED și ESTABLISHED.

Părțile terminale ale conexiunii rămân în starea STABILIT până când una dintre părți procedează la închidere conexiune prin trimiterea unui segment FIN. În timpul unei închideri normale, partea care inițiază acea î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 stări a părții care închide conexiunea

Stări laterale de închidere Eveniment Descriere
STABILIT Aplicația locală solicită ca conexiunea să fie închisă.
TCP trimite FIN/ACK.
FIN-WAIT-1 Partidul de închidere așteaptă răspunsul partenerului. Amintiți-vă 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 în timp ce acceptă datele primite.
TCP primește FIN/ACK.
Trimite un ACK.
TIMP DE AȘTEPTARE Conexiunea este menținută într-o stare nedeterminată pentru a permite sosirea sau eliminarea datelor duplicate sau a FIN duplicat încă existente în rețea. Perioada de așteptare este de două ori mai mare decât durata maximă estimată a segmentului.
ÎNCHIS

Tabelul 10.6 Secvența de stare a partenerului apropiat al conexiunii

Statutul de partener Eveniment Descriere
STABILIT TCP primește FIN/ACK.
ÎNCHIS-ASTEPTĂ 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ă un ACK final.
TCP primește un ACK.
ÎNCHIS S-au eliminat toate informațiile de conectare.

10.17.1 Analizarea stărilor conexiunii TCP

Echipă netstat -an vă permite să verificați starea curentă a conexiunii. Următoarele arată conexiunile în state 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 de implementare

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

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

Unele bune practici de implementare nu sunt acoperite de standarde. De exemplu, securitatea poate fi îmbunătățită prin limitarea utilizării porturilor binecunoscute la procesele privilegiate din sistem, dacă această metodă este acceptată pe sistemul de operare local. Pentru a îmbunătăți performanța, implementările ar trebui să copieze și să mute cât mai puține date trimise sau preluate.

Interfață standard de programare a aplicației nedeterminat(precum și politica de securitate), astfel încât să existe un domeniu de activitate liber pentru experimentarea cu diferite seturi de instrumente software. Cu toate acestea, acest lucru poate duce la interfețe de programare diferite pe fiecare platformă și poate împiedica mutarea aplicației software între platforme.

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

10.19 Lectură suplimentară

Standardul TCP original este definit în RFC 793. Actualizările, corecțiile și cerințele de compatibilitate sunt acoperite în RFC 1122. Kern (Kash) și Partridge (Partridge) au publicat un articol Î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 publicat, de asemenea, mai multe RFC-uri care revizuiesc algoritmi pentru îmbunătățirea performanței.

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 comitetului de auto-configurare IETF. Acest protocol este utilizat în rețelele mici pentru a atribui adrese IP link-local (link-local) gazdelor. Protocolul AutoIP determină singur adresa IP locală de legătură folosind o schemă de negociere cu alte gazde și fără a accesa 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țelei locale de calculatoare acces individual autentificat la rețelele de date de mare viteză.

Protocolul PPPoE combină tehnologia Ethernet cu protocolul PPP, ceea ce vă permite să creați în mod eficient o conexiune separată la un server la distanță pentru fiecare utilizator. Controlul accesului, contabilitatea conexiunii și selecția furnizorului de servicii sunt definite pentru utilizatori, nu pentru gazde. Avantajul acestei abordări este că nici compania de telefonie, nici ISP-ul nu trebuie să ofere suport special pentru aceasta.

Spre deosebire de conexiunile dial-up, conexiunile DSL și modem prin cablu sunt întotdeauna active. Deoarece conexiunea fizică la furnizorul de servicii la distanță este partajată de mai mulți utilizatori, este necesară o metodă de contabilitate care să înregistreze expeditorii de trafic și destinațiile și să taxeze utilizatorii. Protocolul PPPoE permite unui utilizator și unei gazde la distanță care participă la o sesiune de comunicare să învețe reciproc adresele de rețea în timpul unui schimb inițial numit descoperire(descoperire). Odată ce se stabilește o sesiune între un utilizator individual și o gazdă de la distanță (de exemplu, furnizorul de servicii de internet), acea sesiune poate fi monitorizată pentru a face angajări. Multe case, hoteluri și corporații partajează internetul prin linii digitale de abonat folosind tehnologia Ethernet și protocolul PPPoE.

O conexiune 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 lega acele adrese IP la utilizatori și, opțional, la stațiile de lucru, în loc de autentificare bazată doar 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-*pOferă servicii de protocol PPPoE. Mai întâi trebuie să fugiio-pkt-*Cușofer potrivit. Exemplu:

Călătorie prin protocoalele 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 garantată a pachetelor. Mai întâi, are loc o strângere de mână (Bună | Bună | Să discutăm? | Hai.), După care conexiunea este considerată stabilită. În plus, 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 ajuns, dar cu o sumă de control de biți, atunci este trimis din nou („repetă, nu am auzit”). Astfel, TCP este mai fiabil, dar este mai dificil în ceea ce privește implementarea și, în consecință, necesită mai multe cicluri/memorie, ceea ce nu este cea mai recentă valoare 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 omniprezent pe World Wide Web pentru a prelua informații de pe site-uri web. În imagine, lampa se află 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, diferențiat de majuscule. Fiecare server trebuie să accepte cel puțin metodele GET și HEAD. Pe lângă metodele GET și HEAD, metodele POST, PUT și DELETE sunt adesea folosite. Metoda GET este folosită pentru a solicita conținutul resursei 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 de stare. Codul de răspuns este de obicei urmat de o frază explicativă, separată de spațiu, în limba engleză, care explică persoanei motivul unui astfel de răspuns. În cazul nostru, serverul a funcționat fără erori, totul a fost î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ă prin două puncte). Anteturile se termină cu o linie goală, după care pot urma datele.

Browserul meu refuză să deschidă o adresă IPv6 locală, așa că o adresă suplimentară este înregistrată î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://

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 pe 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, deci execuția firului de execuție 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 ( 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 = socket nou (ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Atribuiți socket la punctul final local și ascultați socketurile de intrare încercați ( sListener.Bind(ipEndPoint) ; sListener. Listen(10); // Începeți să ascultați 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 conexiune Socket handler = sListener.Accept(); string data = null; // Am așteptat un client care încearcă să se conecteze cu noi byte bytes = new byte; int bytesRec = handler.Receive(bytes); data += Encoding.UTF8. GetString(bytes, 0, bytesRec); // Afișează datele pe consola Console.Write("Received text: " + date + "\n\n"); // Trimiterea unui răspuns către client\ string reply = "Mulțumesc 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 cu clientul."); 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 punctul final local pentru socket. Înainte de a deschide o priză pentru a asculta conexiuni, trebuie să pregătiți o adresă de punct final local pentru aceasta. Adresa unică a serviciului TCP/IP este determinată de combinația dintre adresa 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 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.

Creați un IPEndPoint pentru server combinând prima adresă IP a gazdei 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. Prin configurarea unui punct final local pentru a asculta conexiuni, puteți crea un socket:

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

Enumerare 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 diferă. Poate include următoarele valori:

dgram

Suporta datagrame. Valoarea Dgram necesită să specificați 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ă poată identifica un socket de flux TCP, programul server trebuie să-și numească socket-ul:

SListener.Bind(ipEndPoint);

Metoda Bind() leagă un socket la un punct final local. Trebuie să apelați metoda Bind() î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 aștepta încercările de conectare:

SListener.Listen(10);

Parametrul definește întârziere (întârziere) A care specifică numărul maxim de conexiuni care așteaptă să fie procesate î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 completează asocierea dintre numele client și server. Metoda Accept() blochează firul de execuție al programului apelant până când este primită o conexiune.

Metoda Accept() preia prima cerere de conexiune din coada de cereri în așteptare și creează un nou socket pentru a o gestiona. În timp ce noul socket este creat, socketul original continuă să asculte și poate fi utilizat cu multithreading pentru a accepta mai multe cereri de conexiune de la clienți. Nicio aplicație server nu ar trebui să închidă soclul de ascultare. Trebuie să continue să funcționeze împreună cu 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, așteaptă 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 prize.

Metoda Send() scrie datele de ieșire în soclul la care este conectat. Metoda Receive() citește datele primite pe soclul de flux. Când utilizați un sistem bazat pe TCP, trebuie stabilită o conexiune între socketuri înainte ca metodele Send() și Receive() să fie executate. Protocolul exact între două entități care interacționează trebuie stabilit î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 pe soclu, a primi- încetează să mai primească date pe priză și trimite- oprește soclul să trimită date.

Socket-ul este închis atunci când este apelată metoda Close(), care setează, de asemenea, proprietatea Connected a socketului la false.

Client pe TCP

Funcțiile care sunt folosite pentru a crea o aplicație client sunt mai mult sau mai puțin ca o aplicație server. În ceea ce privește serverul, 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.

Top articole similare