TCP drieweghandshake - SYN- en ACK-vlaggen

De UDP-header is altijd 64 bits lang. De velden die zijn gedefinieerd in het UDP-segment (zie afbeelding) omvatten het volgende:
1. Bronpoort: bronpoortnummer (16 bits)
2. Bestemmingspoort: bestemmingspoortnummer (16 bits)
3. Berichtlengte: UDP-headerlengte en UDP-gegevens(16 bit)
4. Checksum: berekende checksum van header- en datavelden (16 bits)
5. Gegevens: gegevens van het bovenste laagprotocol (ULP) (variabele lengte)
Voorbeelden van protocollen die UDP gebruiken: TFTP, SNMP, Netwerkbestand Systeem (NFS) en domein Naam Systeem(DNS).

De TCP-header bevat informatie die is gedefinieerd TCP-protocol. IN deze sectie De componenten van de TCP-header worden beschreven.

TCP-segmenten worden verzonden met behulp van IP-pakketten. De TCP-header volgt de IP-header. Deze scheiding maakt het bestaan ​​van andere protocollen op hostniveau dan TCP mogelijk. TCP-headervelden omvatten het volgende:

Bronpoort: Bronpoortnummer (16 bits)

Bestemmingspoort: Bestemmingspoortnummer (16 bits)

Volgnummer: serienummer eerste octet aan gegevens
segment dat wordt gebruikt om ervoor te zorgen dat binnenkomende gegevens correct worden geordend
(32 bits)

Bevestigingsnummer: volgende verwachte octet
TCP (32-bits)

Lengte header: aantal 32-bits woorden in de header (4 bits)

Gereserveerd: ingesteld op 0 (3 bits)

Besturingsbits: Besturingsfuncties zoals instellen,
overbelasting en sessiebeëindiging (9 bits). Een enkel bitje dat iets bijzonders heeft
een waarde die vaak wordt gezien als een vlag.

Venster: aantal bytes dat het apparaat wil accepteren (16 bits)

Checksum: De berekende checksum van de header en
gegevens (16 bits)

Dringend: geeft het einde van urgente gegevens aan (16 bits)

Opties: Momenteel is er één optie gedefinieerd: maximale grootte
TCP-segment (0 of 32 bits)

Gegevens: gegevens van het bovenste laagprotocol (ULP).
(variabele lengte)

0 - 3

4 - 9

10 - 15

16 - 31

Bronpoort

Haven van bestemming, Haven van bestemming

Serienummer, Volgnummer (SN)

Bevestigingsnummer

Lengte kop

Gereserveerd

Vlaggen

Venstergrootte

Controleer som

Belangindicator

Opties (optioneel, maar bijna altijd gebruikt)

160/192+

Gegevens

P Bronpoort, bestemmingspoort

Deze 16-bits velden bevatten getallen havens - getallen die worden bepaald doorspeciale lijst .

Bronpoort identificeert de clienttoepassing van waaruit de pakketten zijn verzonden. Op basis van dit nummer worden responsgegevens naar de klant verzonden.

Haven van bestemming identificeert de poort waarnaar het pakket is verzonden.

Serienummer

Het volgnummer dient twee doelen:

  1. Als de SYN-vlag is ingesteld, is dit het initiële volgnummer - ISN (Initial Sequence Number) en de eerste byte aan gegevens die worden overgedragen naar volgende pakket, zal een nummer hebben dat gelijk is aan ISN + 1.
  2. Anders, als SYN niet is ingesteld, heeft de eerste byte aan gegevens die in een bepaald pakket wordt verzonden dit volgnummer

Omdat een TCP-stream doorgaans langer kan zijn dan het aantal verschillende statussen van dit veld, moeten alle bewerkingen met een volgnummer modulo 2 worden uitgevoerd 32 . Dit plaatst een praktische beperking op het gebruik van TCP. Als de overdrachtssnelheid communicatie systeem is zodanig dat tijdens de MSL (maximale segmentlevensduur) het volgnummer overloopt, waarna er twee segmenten met hetzelfde nummer in het netwerk kunnen verschijnen, gerelateerd aan verschillende delen streamen, en de ontvanger ontvangt onjuiste gegevens.

N bevestigingsnummer

Bevestigingsnummer (ACK SN)(32 bits) - als de ACK-bit is ingesteld, bevat dit veld het volgnummer van het octet dat de zender van dit segment wil ontvangen. Dit betekent dat alle voorgaande octetten (met nummers van ISN+1 tot en met ACK-1) succesvol zijn ontvangen.

D Kopregel (data-offset)

Dit veld specificeert de grootte van de TCP-pakketheader in woorden van 4 bytes (4 octet). Minimale maat is 5 woorden en het maximum is 15, wat respectievelijk 20 en 60 bytes is. De offset wordt berekend vanaf het begin van de TCP-header.

3 gereserveerd

Gereserveerd (6 bits) voor toekomstig gebruik en moet op nul worden gezet. Hiervan zijn er al twee (5e en 6e) gedefinieerd:

  • CWR (Congestion Window Reduced) - Congestion Window Reduced veld - vlag ingesteld door de afzender om aan te geven dat een pakket is ontvangen met de ECE-vlag ingesteld (RFC 3168)
  • ECE (ECN-Echo) - ECN Echo-veld - geeft aan dat dit knooppunt in staat is tot ECN (Explicit Congestion Notification) en om de afzender te waarschuwen over netwerkcongestie (RFC 3168)

F vertragingen (controlebits)

Dit veld bevat 6-bits vlaggen:

  • URG-veld "Belangindex" betrokken (Engels) Het dringende aanwijzerveld is aanzienlijk)
  • ACK-veld "Bevestigingsnummer" betrokken (Engels) Het bevestigingsveld is aanzienlijk)
  • PSH - (Engelse Push-functie) instrueert de ontvanger om de gegevens die zijn verzameld in de ontvangende buffer naar de gebruikersapplicatie te pushen
  • RST - verbindingen verbreken, buffer resetten (buffer wissen) (eng. Reset de verbinding)
  • SYN - volgnummers synchroniseren
  • FIN (Engelse finale, bit) - de vlag geeft, indien ingesteld, de voltooiing van de verbinding aan (Engels. FIN-bit gebruikt voor het beëindigen van de verbinding).

Venstergrootte

Aantal databytes vanaf laatste nummer bevestigingen die de afzender kan accepteren van dit pakket. Met andere woorden: de afzender van het pakket heeft een buffer van bytes van “venstergrootte” om gegevens te ontvangen.

NAAR controlesom

Veld controlesom is het 16-bits complement van de som van alle 16-bits woorden van de header (inclusief de pseudo-header) en gegevens. Als het segment waarvoor de controlesom wordt berekend een lengte heeft die geen veelvoud van 16 bits is, wordt de segmentlengte vergroot tot een veelvoud van 16 door er rechts nul opvulbits aan toe te voegen. Opvulbits (0) worden niet verzonden in het bericht en dienen alleen om de controlesom te berekenen. Bij het berekenen van de controlesom wordt aangenomen dat de waarde van het controlesomveld zelf 0 is.

U belangrijkheidsindicator

De 16-bits waarde van de positieve verschuiving ten opzichte van het volgnummer in dit segment. Dit veld specificeert het octetvolgnummer waarmee de urgente gegevens worden beëindigd. Er wordt alleen rekening gehouden met dit veld voor pakketten waarvoor de URG-vlag is ingesteld. Is gebruikt voorgegevens buiten de band .

Over de optie

Kan in sommige gevallen worden gebruikt om het protocol uit te breiden. Soms gebruikt voor testen. Op dit moment opties omvatten bijna altijd 2 bytes GEEN P (V in dit geval 0x01) en 10 bytes specificeren tijdstempels . U kunt de lengte van het optieveld berekenen met behulp van de waarde van het offsetveld.

M mechanisme van het protocol

in tegenstelling tot traditioneel alternatief- UDP, dat onmiddellijk kan beginnen met het verzenden van pakketten, TCP brengt verbindingen tot stand die moeten worden gemaakt voordat gegevens worden verzonden. TCP-verbinding kan worden onderverdeeld in 3 fasen:

  • Een verbinding tot stand brengen
  • Data overdracht
  • De verbinding beëindigen

MET TCP-sessiestatus

Vereenvoudigd TCP-statusdiagram. Meer details binnen TCP EFSM-diagram (in Engels)

TCP-sessiestatussen

GESLOTEN

De beginstatus van het knooppunt. Eigenlijk fictief

LUISTEREN

De server wacht op verbindingsverzoeken van de client

SYN-VERZONDEN

De client heeft een verzoek naar de server gestuurd om een ​​verbinding tot stand te brengen en wacht op een reactie

SYN-ONTVANGEN

De server heeft een verbindingsverzoek ontvangen, een antwoordverzoek verzonden en wacht op bevestiging

GEVESTIGD

Verbinding tot stand gebracht, gegevensoverdracht bezig

FIN-WACHT-1

Een van de partijen (laten we het knooppunt-1 noemen) voltooit de verbinding door een segment met de FIN-vlag te verzenden

DICHT-WACHT

De andere kant (knooppunt-2) komt in deze toestand door op zijn beurt een ACK-segment te verzenden en gaat door met de eenrichtingstransmissie

FIN-WACHT-2

Knooppunt-1 ontvangt ACK, gaat verder met lezen en wacht op het ontvangen van een segment met de FIN-vlag

LAATSTE-ACK

Knooppunt-2 beëindigt de transmissie en verzendt het segment met de FIN-vlag

TIJD WACHT

Knooppunt-1 ontving een segment met de FIN-vlag, stuurde een segment met de ACK-vlag en wacht 2*MSL seconden voordat hij uiteindelijk de verbinding verbrak

SLUITEND

Beide partijen hebben tegelijkertijd de verbindingssluiting gestart: na het verzenden van een segment met de FIN-vlag ontvangt knooppunt 1 ook een FIN-segment, verzendt een ACK en wacht op een ACK-segment (bevestiging van zijn verzoek om de verbinding te verbreken)

U een verbinding tot stand brengen

Het proces van het starten van een TCP-sessie (ook wel een "handshake" genoemd ( Engels handdruk

)), bestaat uit drie stappen. 1. De client, die een verbinding tot stand wil brengen, stuurt de server een segment met een volgnummer en.

  • SYN-vlag
  • De server ontvangt het segment, onthoudt het volgnummer en probeert een socket (buffers en controlegeheugenstructuren) te creëren om de nieuwe client te bedienen.
  • Als dit lukt, stuurt de server de client een segment met een volgnummer en de vlaggen SYN en ACK, en gaat naar de status SYN-RECEIVED.

In geval van een storing stuurt de server de client een segment met de RST-vlag.

  • 2. Als de client een segment met de SYN-vlag ontvangt, onthoudt hij het volgnummer en verzendt hij het segment met de ACK-vlag.
  • Als het tegelijkertijd ook de ACK-vlag ontvangt (wat meestal gebeurt), gaat het naar de status ESTABLISHED.
  • Als de client een segment met de RST-vlag ontvangt, stopt hij met verbinding maken.

Als de client binnen 10 seconden geen reactie ontvangt, herhaalt hij het verbindingsproces opnieuw.

  • 3. Als de server in de SYN-RECEIVED-status een segment met de ACK-vlag ontvangt, gaat deze over naar de ESTABLISHED-status.

Anders sluit het na een time-out de socket en komt in de GESLOTEN status. Het proces heet "matching in drie stappen" ( Engels handdruk in drie richtingen segmenten (SYN richting de server, ACK richting de client, SYN richting de client, ACK richting de server), in de praktijk worden drie segmenten gebruikt om tijd te besparen.

Voorbeeld van een basisgoedkeuring in 3 stappen:

TCP A TCP B

1. GESLOTEN LUISTEREN

2. SYN-VERZONDEN --> --> SYN-ONTVANGEN

3. GEVESTIGD<-- <-- SYN-RECEIVED

4. GEVESTIGD --> -->VESTIGD

5. GEVESTIGD<-- <-- ESTABLISHED

Op regel 2 begint TCP A met het verzenden van een SYN-segment dat het gebruik van volgnummers aangeeft, beginnend met 100. Op regel 3 verzendt TCP B een SYN en een bevestiging voor de ontvangen SYN naar TCP A. Opgemerkt moet worden dat het bevestigingsveld geeft aan dat TCP B wacht op ontvangst van het volgnummer 101, waarmee SYN-nummer 100 wordt bevestigd.

Op regel 4 antwoordt TCP A met een leeg segment met een ACK voor het SYN-segment van TCP B; op lijn 5 verzendt TCP B enkele gegevens. Houd er rekening mee dat het segmentbevestigingsnummer op regel 5 (ACK=101) hetzelfde is als het volgnummer op regel 4 (SEQ=101), aangezien ACK geen volgnummerruimte in beslag neemt (als dit wordt gedaan, moet u de bevestigingen bevestigen - ACK voor ACK). Nagle's algoritme en langzame start

Bij het uitwisselen van gegevens gebruikt de ontvanger het volgnummer in de ontvangen segmenten om de oorspronkelijke volgorde te herstellen. De ontvanger informeert de verzendende kant over het volgnummer tot waar hij met succes gegevens heeft ontvangen, inclusief dit in het veld "bevestigingsnummer". Alle ontvangen gegevens binnen het bereik van bevestigde sequenties worden genegeerd. Als het ontvangen segment een volgnummer bevat dat groter is dan verwacht, worden de gegevens van het segment gebufferd, maar wordt het bevestigde volgnummer niet gewijzigd. Als vervolgens een segment wordt ontvangen dat overeenkomt met het verwachte volgnummer, wordt de volgorde van de gegevens automatisch hersteld op basis van de volgnummers in de segmenten.

Om ervoor te zorgen dat de verzendende kant niet meer gegevens verzendt dan de ontvanger kan verwerken, bevat TCP flowcontrols. Gebruik hiervoor het veld "venster". In segmenten die van de ontvanger naar de zendende kant worden verzonden, wordt de huidige grootte van de ontvangende buffer aangegeven in het “venster”-veld. De verzendende kant behoudt de venstergrootte en verzendt niet meer gegevens dan aangegeven door de ontvanger. Als de ontvanger een venstergrootte van nul heeft opgegeven, worden er geen gegevens in de richting van dit knooppunt verzonden totdat de ontvanger een grotere venstergrootte meldt.

In sommige gevallen kan de verzendende applicatie expliciet verzoeken dat de gegevens achtereenvolgens naar de ontvangende applicatie worden gepusht zonder deze te bufferen. Hiervoor wordt de PSH-vlag gebruikt. Als de PSH-vlag wordt gedetecteerd in het ontvangen segment, retourneert de TCP-implementatie alle momenteel gebufferde gegevens naar de ontvangende applicatie. Push wordt bijvoorbeeld gebruikt in interactieve toepassingen. Bij netwerkterminals heeft het geen zin om te wachten op gebruikersinvoer nadat hij klaar is met het typen van een opdracht. Daarom moet het laatste segment dat de opdracht bevat de PSH-vlag bevatten, zodat de toepassing aan de ontvangende kant kan beginnen met het uitvoeren ervan.

Z het beëindigen van de verbinding

Het beëindigen van een verbinding kan in drie stappen worden overwogen:

  1. Het verzenden van de FIN-vlag naar de server vanaf de client om de verbinding te verbreken.
  2. De server verzendt de clientantwoordvlaggen ACK, FIN, wat aangeeft dat de verbinding is gesloten.
  3. Na ontvangst van deze vlaggen verbreekt de client de verbinding en stuurt een ACK naar de server om te bevestigen dat de verbinding gesloten is.

Met behulp van een programma dat het verkeer en de gebruikte protocollen analyseert - Wireshark, kunt u de werking van een drietraps TCP-handshake observeren:


Stap 1

De TCP-client begint een drieweg-handshake door een segment te verzenden terwijl de controlevlag is ingesteld SYN(Volgnummer synchroniseren) door de oorspronkelijke waarde op te geven in het volgnummerveld in de koptekst. Dit is de beginwaarde van het volgnummer, bekend als het startvolgnummer ( IS), wordt willekeurig geselecteerd en wordt gebruikt om de gegevensstroom van de client naar de server voor die sessie te volgen. Het ISN in de header van elk segment wordt met één verhoogd voor elke byte aan gegevens die van de client naar de server wordt verzonden, terwijl de gegevensuitwisseling doorgaat.

De afbeelding laat zien hoe de uitvoer van de protocolanalysator de SYN-controlevlag en het relatieve volgnummer toont.

De SYN-controlevlag is ingesteld en het relatieve volgnummer is 0. Hoewel de protocolanalysatorgrafiek relatieve waarden aangeeft voor volg- en bevestigingsnummers, zijn de echte waarden binaire 32-bits getallen. We kunnen de werkelijke aantallen die in de segmentheaders worden verzonden bepalen door het gebied "Packet Bytes" te onderzoeken. Hier ziet u de vier bytes die worden weergegeven in hexadecimaal formulier.

Stap 2

De TCP-server moet de ontvangst van een SYN-segment van de client bevestigen om een ​​sessie van de client naar de server tot stand te brengen. Om dit te doen, stuurt de server het segment terug naar de client met de ACK-vlag ingesteld, wat aangeeft dat het bevestigingsnummerveld is ingeschakeld. Als deze vlag op het segment is ingesteld, herkent de client dit als een bevestiging dat de server een SYN heeft ontvangen van het TCP van de client.

Het TCP/IP-protocol werd voor het eerst ontwikkeld begin jaren zeventig en werd gebruikt om het ARPANET te creëren. De technologie is ontwikkeld als onderdeel van een onderzoeksproject dat gericht was op het bestuderen van de potentiële mogelijkheid om computers te combineren binnen hetzelfde lokale of virtuele internetwerknetwerk.

Het tot stand brengen van een verbinding in TCP gebeurt met behulp van een speciaal clientprogramma, zoals een browser, e-mailprogramma of berichtenclient.

TCP-structuur

Dankzij de TCP/IP-structuur kunt u toegang tot externe computers creëren en individuele apparaten combineren om lokale netwerken te creëren die gescheiden van de openbare netwerken functioneren. TCP is een betrouwbaar protocol voor gegevensoverdracht. Alle informatie die via het netwerk wordt verzonden, wordt dus gegarandeerd door de geadresseerde ontvangen, d.w.z. de gebruiker aan wie de gegevens zijn verstrekt.

Een alternatief voor TCP is UDP. Een belangrijk verschil tussen deze netwerken is dat TCP eerst een vertrouwde verbinding tot stand moet brengen tussen de zender en de ontvanger van de informatie. Zodra de verbinding tot stand is gebracht, worden de gegevens overgedragen en begint de procedure voor het beëindigen van de verbinding. UDP brengt onmiddellijk de overdracht van de benodigde informatiepakketten naar de gebruiker tot stand, zonder eerst een kanaal te creëren.

Gegevens verzenden via TCP

Nadat een verbinding tot stand is gebracht, verzendt TCP gegevens langs gecreëerde routes in overeenstemming met de IP-adressen van de afzender en ontvanger van de informatie. Een IP-adres is een unieke identificatie van elk netwerkapparaat op internet, en daarom kan een pakket dat via de gecreëerde tunnel wordt verzonden, niet verloren gaan of per ongeluk naar een andere gebruiker worden verzonden.

Op het fysieke niveau van datatransmissie heeft informatie de vorm van frequenties, amplitudes en andere signaalvormen, die al worden verwerkt door de netwerkkaart van de ontvanger.

Kanaalprotocollen zijn verantwoordelijk voor het verwerken van informatie door een computer en het verzenden ervan naar andere componenten, waaronder Ethernet, ATM, SLIP, IEEE 802.11. Deze kanalen zorgen niet alleen voor datatransmissie, maar ook voor een vorm van bezorging bij de ontvanger. In IEEE 802.11-netwerken wordt informatie dus verzonden met behulp van een draadloos radiosignaal. In dit geval wordt het signaal geleverd door de netwerkkaart van de computer, die ook een eigen MAC-code heeft. Bij Ethernet vindt alle datatransmissie plaats via een kabelverbinding.

Video over het onderwerp

In moderne omstandigheden zijn de activiteiten van de samenleving en de beschaving onmogelijk zonder het gebruik van middelen voor snelle informatie-uitwisseling. Mondiale computernetwerken zijn ontworpen om dit probleem op te lossen.

Een mondiaal netwerk (GCN) is een netwerk dat bestaat uit computers die uitgestrekte gebieden bestrijken, met een onbeperkt aantal computersystemen in dit netwerk. De belangrijkste voorwaarde voor het functioneren van dergelijke netwerken is de onmiddellijke overdracht van informatie via het netwerk, ongeacht de afstand van de zendende en ontvangende computer.

Het mondiale netwerk verschilt in de eerste plaats van het lokale netwerk door de lagere gegevensoverdrachtsnelheden. Mondiale netwerken werken via TCP/IP, MPLS, ATM en enkele andere protocollen. Het bekendste hiervan is het TCP/IP-protocol, dat subprotocollen van verschillende niveaus omvat: applicatie, transport, netwerk, fysiek en kanaal.

Op applicatieniveau werken de meeste programma's met hun eigen protocollen die algemeen bekend zijn bij gewone pc-gebruikers (HTTP, WWW, FTP, enz.). Deze protocollen zorgen voor visualisatie en weergave van de door de gebruiker vereiste informatie.

Het transportprotocol is verantwoordelijk voor het leveren van gegevens aan precies de applicatie die deze kan verwerken. Het heet TCP.

De netwerklaag is feitelijk de ontvangende laag bij het verzenden van informatie en het verzenden van verzoeken naar lagere lagen om alle informatie te verkrijgen. Dit wordt het IP-protocol genoemd.

De fysieke en linklagen zijn verantwoordelijk voor het definiëren van de voorwaarden en methoden voor het verzenden van informatie.

Het bekendste wereldwijde netwerk is WWW (World Wide Web), een verzameling servers die informatie opslaan die nodig is voor gebruikers, en computers die zowel informatie van servers kunnen ontvangen als deze naar deze servers kunnen uploaden. WWW onderscheidt zich door zijn gemak en gebruiksgemak, evenals lage vereisten voor gegevensoverdrachtsnelheid. Hierdoor kon dit netwerk zich in iets meer dan tien jaar ontwikkelen.

Video over het onderwerp

Het is gebruikelijk om te verwijzen naar een symbolische aanduiding die de numerieke adressering op basis van IP-adressen op internet vervangt. Numerieke adressering, gebruikt bij de verwerking van routeringstabellen, is ideaal voor computergebruik, maar levert voor de gebruiker aanzienlijke problemen op om te onthouden. Domeinnamen met een geheugensteuntje komen te hulp.

Internetverbindingen worden tot stand gebracht met behulp van numerieke groepen van 4 waarden, gescheiden door het symbool “.” en IP-adressen gebeld. De symbolische namen van het domeinnaamcomplex zijn een service die is ontworpen om het gemakkelijker te maken het vereiste IP-adres op het netwerk te vinden. De technische indicator van een domeinnaam is de “.”. in het e-mailadres van de gebruiker. In het google.com-adres is de domeinnaam dus com Naam kan geen toegang bieden tot de vereiste internetbron. De procedure voor het gebruik van een geheugensteuntje bestaat uit twee fasen: - IP-adressen op naam in het hosts-bestand met correspondentietabellen tussen het IP-adres en de computernaam; De taak van de DNS-service is het verkrijgen van IP-adressen voor het tot stand brengen van een verbinding, waardoor deze service hulp biedt ten opzichte van het TCP/IP-protocol. is een scheidingsteken voor domeinnamen, hoewel er voor praktische doeleinden meestal wordt aangenomen dat dit verwijst naar een hoofddomein dat geen eigen aanduiding heeft. De root - de volledige set internethosts - is verdeeld in: - eerste niveau - gov, edu, com, net - uk, jp, ch, enz.; Het behoud van de vertrouwde boomstructuur van domeinnamen leidde tot het gebruik van gevestigde terminologie: root, tree nodes, leaf. De term “host” in deze hiërarchie wordt toegewezen aan een blad dat geen enkel knooppunt eronder heeft. De volledige hostnaam wordt een opeenvolgende lijst van alle tussenliggende knooppunten tussen de root en het leaf, gescheiden door het teken "." van links naar rechts: ivan.net.abcd.ru, waarbij ru de wortel van de boom is, abcd de naam van de organisatie is, ivan het blad van de boom (host).

Video over het onderwerp

Bronnen:

  • Internetdomeinnaamsysteem in 2018

Ik vind de hele serie artikelen erg leuk, en ik heb mezelf altijd al als vertaler willen uitproberen. Misschien lijkt het artikel te voor de hand liggend voor ervaren ontwikkelaars, maar het lijkt mij dat het in ieder geval nuttig zal zijn.

Hallo, mijn naam is Glenn Fiedler en ik heet je welkom bij het eerste artikel in mijn online boek, Netwerkprogrammering voor game-ontwikkelaars.

In dit artikel beginnen we met de meest elementaire aspecten van netwerkprogrammering: het ontvangen en verzenden van gegevens via het netwerk. Het ontvangen en verzenden van gegevens is het meest fundamentele en eenvoudigste onderdeel van het hele scala aan taken dat netwerkprogrammeurs uitvoeren, maar het is vaak moeilijk om te bepalen welke manier het beste is om te werk te gaan. Besteed voldoende aandacht aan dit onderdeel - als je met een misverstand blijft zitten, kan dit later ernstige gevolgen hebben voor je multiplayer-game!

Je hebt waarschijnlijk al iets gehoord over sockets, en je weet misschien dat er twee hoofdtypen zijn: TCP en UDP. Het eerste dat u moet beslissen bij het ontwikkelen van een multiplayergame, is welk type sockets u wilt gebruiken: TCP, UDP of beide?

De keuze voor het sockettype hangt volledig af van het genre van de game die je ontwikkelt. In deze serie artikelen ga ik ervan uit dat je een actiespel schrijft, zoals Halo, Battlefield 1942, Quake, Unreal, CounterStrike, Team Fortress, enz.

Nu zullen we de eigenschappen van elk type stopcontact nader bekijken (rekening houdend met het feit dat we een actiespel aan het ontwikkelen zijn), en wat dieper ingaan op de details van hoe internet werkt. Na een gedetailleerde beoordeling wordt de juiste optie duidelijk!

TCP staat voor ‘transmission control protocol’ en IP staat voor ‘internetprotocol’. Samen ondersteunen ze bijna alles wat u online doet, van surfen op het web tot IRC en e-mailcommunicatie - allemaal draaiend op TCP/IP.

Als u ooit TCP-sockets heeft gebruikt, moet u weten dat TCP een protocol is dat gebruik maakt van het principe van een betrouwbare verbinding. Dit betekent dat u een verbinding tot stand brengt tussen twee computers en vervolgens gegevens tussen deze computers verzendt, net alsof u informatie naar een bestand op de ene computer schrijft en deze uit hetzelfde bestand op een andere computer leest.

In dit geval wordt de verbinding als betrouwbaar en consistent beschouwd, dat wil zeggen dat alle informatie die u verzendt gegarandeerd de ontvanger bereikt in dezelfde volgorde als waarin deze is verzonden. Bovendien kan een TCP-verbinding worden beschouwd als een continue stroom gegevens; het protocol zorgt er zelf voor dat de gegevens in pakketten worden opgedeeld en over het netwerk worden verzonden.

Nog een keer - alles is net zo eenvoudig als normaal schrijven of lezen uit een bestand. Elementaire Watson!

Maar dit gebruiksgemak is compleet anders dan wat er feitelijk "onder de motorkap" gebeurt, op een lager niveau: het IP-protocolniveau.

Op dit niveau bestaat er geen concept van verbinding; in plaats daarvan worden individuele pakketten van de ene computer naar de andere verzonden. Je kunt dit proces zien als het doorgeven van een briefje van de ene persoon aan de andere in een kamer vol mensen: uiteindelijk komt het briefje bij de juiste persoon terecht, maar gaat het tegelijkertijd door vele handen.

Er is echter geen garantie dat het briefje de geadresseerde zal bereiken. De afzender stuurt eenvoudigweg een briefje in de hoop dat het aankomt, maar weet niet eens of het bericht is aangekomen of niet - totdat de ontvanger besluit terug te schrijven.
Uiteraard is alles in werkelijkheid iets ingewikkelder, omdat de verzendende computer niet de exacte volgorde kent van de computers op het netwerk waarlangs het pakket moet worden verzonden, zodat het zo snel mogelijk aankomt. Soms verzendt IP meerdere kopieën van hetzelfde pakket, die verschillende routes kunnen volgen om de bestemming te bereiken - en waarschijnlijk op verschillende tijdstippen aankomen.

Wat als we informatie tussen computers willen overbrengen, niet in de stijl van het lezen/schrijven van bestanden, maar door het direct verzenden en ontvangen van individuele pakketten?

Welnu, we kunnen dit doen met behulp van UDP. UDP staat voor “user datagram protocol” en het draait bovenop IP (zoals TCP), maar in plaats van een hoop functionaliteit toe te voegen is het slechts een kleine toevoeging aan IP.

Met behulp van UDP kunnen we een pakket naar een specifiek IP-adres (bijvoorbeeld 112.140.20.10) en poort (bijvoorbeeld 52423) sturen, en het wordt van computer naar computer verzonden totdat het zijn bestemming bereikt (of verloren raakt onderweg). manier).

Tegelijkertijd zitten we aan de ontvangerkant gewoon te wachten, luisterend naar een bepaalde poort (in ons geval 52423), en als er een pakketje van iemand binnenkomt (onthoud dat er geen verbindingen worden gebruikt), krijgen we hierover een melding met het adres en de poort van de verzendende computer, de pakketgrootte, en daarna kunnen we de gegevens uit dit pakket lezen.

Het UDP-protocol garandeert geen gegevenslevering. In de praktijk komen de meeste pakketten uiteraard wel aan, maar er is altijd een verlies van ongeveer 1-5%, en soms zijn er perioden waarin pakketten helemaal niet aankomen (onthoud dat er tussen de afzender en de ontvanger mogelijk duizenden computers zijn, waarvan er één kan uitvallen of kapot gaat).

UDP garandeert ook niet de volgorde waarin pakketten worden afgeleverd. U kunt vijf pakketten in de juiste volgorde verzenden - 1, 2, 3, 4, 5 - maar het kan zijn dat ze in een geheel andere volgorde aankomen - bijvoorbeeld 3, 1, 2, 5, 4. Ook in de praktijk zullen ze hoogstwaarschijnlijk komen meestal in de juiste volgorde aan, maar daar kun je niet op vertrouwen!

Hoewel UDP niet veel toevoegt aan IP, garandeert het ten slotte wel één ding. Als u een pakket doorstuurt, komt het geheel of helemaal niet aan. Als u dus een pakket van 256 bytes naar een andere computer verzendt, kan deze niet alleen de eerste 100 bytes van het pakket ontvangen; hij moet alle 256 bytes ontvangen. Dit is eigenlijk het enige dat het UDP-protocol garandeert: al het andere valt op uw schouders.

We moeten dus beslissen: moeten we TCP- of UDP-sockets gebruiken? Laten we eens kijken naar hun eigenschappen:

  • Maakt gebruik van het verbindingsprincipe
  • Garandeert levering en doorlooptijd
  • Splitst informatie automatisch op in pakketten
  • Zorgt ervoor dat data niet te intensief wordt verzonden (data flow control)
  • Gemakkelijk te gebruiken - zoals schrijven/lezen vanuit een bestand
UDP:
  • Maakt geen gebruik van het verbindingsprincipe - u zult het handmatig moeten implementeren
  • Garandeert niet de levering en volgorde van levering van pakketten - ze kunnen in de verkeerde volgorde aankomen, met duplicaten, of helemaal niet aankomen!
  • U moet de gegevens handmatig in pakketten splitsen en deze verzenden
  • Je moet oppassen dat je de gegevens niet te intensief verzendt
  • Als een pakket verloren gaat, moet u het op de een of andere manier volgen en, indien nodig, opnieuw verzenden
Met zo'n lijst lijkt de oplossing voor de hand te liggen: TCP implementeert alle functionaliteit die we nodig hebben en is gemakkelijker te gebruiken, terwijl het gebruik van UDP aambeien belooft dat alles handmatig, helemaal opnieuw, wordt geschreven. Dus we gebruiken TCP, toch?

Maar nee.

Het gebruik van TCP is waarschijnlijk de grootste fout die je kunt maken bij het ontwikkelen van een multiplayergame. Om te begrijpen waarom, laten we eens kijken naar wat TCP zo gemakkelijk te gebruiken maakt!

Hoe TCP werkt
TCP en UDP werken beide bovenop IP, maar in werkelijkheid zijn ze totaal verschillend. UDP gedraagt ​​zich vrijwel hetzelfde als IP, terwijl TCP de gebruiker wegneemt van alle pakketproblemen, waardoor de interactie lijkt op het lezen/schrijven naar een bestand.

Dus hoe doet hij het?

Ten eerste maakt TCP gebruik van een datastroomabstractie: u kunt eenvoudigweg bytes aan gegevens naar die stroom schrijven, en TCP zorgt ervoor dat deze op zijn bestemming terechtkomt. Omdat IP gegevens in pakketten verzendt en TCP bovenop IP draait, moet TCP de invoerstroom van de gebruiker opsplitsen in afzonderlijke pakketten. Binnen TCP verzamelt een bepaalde logica dus gegevens in een wachtrij, en als er genoeg zijn, vormt het een pakket en stuurt het naar de bestemming.

Dit gedrag kan een probleem zijn voor ons multiplayerspel als we zeer kleine pakketten moeten overbrengen. Het kan gebeuren dat TCP besluit onze gegevens niet te verzenden voordat deze voldoende zijn verzameld om een ​​pakket van een bepaalde grootte te vormen (bijvoorbeeld meer dan honderd bytes). En dit is een groot probleem, omdat het nodig is om gegevens van de client (toetsaanslagen van de speler) zo snel mogelijk naar de server over te brengen, en als er vertragingen zijn als gevolg van gegevensbuffering door het protocol, dan voor de speler aan de clientzijde de game zal op een prettige manier niet de meest zijn. In dit geval zal het updaten van spelobjecten met vertraging en zelden plaatsvinden, terwijl we objecten op tijd en vaak moeten updaten.

TCP heeft een optie om dit op te lossen - "TCP_NODELAY". Het vertelt het protocol niet te wachten tot de gegevens zich in de verzendwachtrij hebben verzameld, maar deze onmiddellijk te verzenden.

Helaas heeft TCP, zelfs als deze optie is geïnstalleerd, veel problemen bij gebruik in online games.

De wortel van alle problemen ligt in de manier waarop TCP omgaat met verloren of niet in orde zijnde pakketten, waardoor de illusie ontstaat van een betrouwbare en consistente verbinding.

Hoe TCP de betrouwbaarheid van verbindingen garandeert
Bij het verzenden verdeelt TCP de gegevensstroom in afzonderlijke pakketten, stuurt deze via het netwerk door met behulp van het onbetrouwbare IP-protocol en reconstrueert vervolgens de oorspronkelijke stroom van de ontvangen pakketten op de ontvangende computer.

Maar wat gebeurt er als een van de pakketten niet aankomt? Of als de pakketten niet in de juiste volgorde aankomen, of met duplicaten?

Zonder al te diep in te gaan op de details van hoe TCP werkt (en dit is echt een heel complex onderwerp - je kunt het lezen in TCP/IP Illustrated), ziet het proces er als volgt uit: TCP verzendt een pakket en stelt vast dat het pakket niet is aangekomen en verzendt hetzelfde pakket opnieuw naar de ontvanger. Dubbele pakketten worden geëlimineerd aan de kant van de ontvanger, en pakketten die in de verkeerde volgorde aankomen, worden opnieuw gerangschikt, zodat alles is zoals het zou moeten zijn: betrouwbaar en in orde.

Het probleem is dat wanneer TCP de datastroom op deze manier ‘synchroniseert’ en een pakket verloren gaat, de transmissie stopt totdat het verloren pakket opnieuw wordt verzonden (en ontvangen door de bestemming). Als er tijdens het wachten nieuwe gegevens binnenkomen, worden deze in de wachtrij geplaatst en kunt u deze pas lezen als het verloren pakket arriveert. Hoe lang duurt het om een ​​pakket opnieuw te verzenden? Het duurt minimaal de retourtijd van het pakket (wanneer TCP bepaalt welk pakket opnieuw moet worden verzonden), plus de tijd om het verloren pakket opnieuw af te leveren. Dus als de ping tussen computers 125 ms bedraagt, zal het opnieuw verzenden van het pakket ongeveer een vijfde van een seconde duren, en in het ergste geval zelfs een halve seconde (stel je voor dat het opnieuw verzonden pakket plotseling ook verloren gaat). Veselukha!

Waarom je TCP nooit zou moeten gebruiken voor multiplayer-spellen
Het probleem met het gebruik van TCP in online games is dat games, in tegenstelling tot browsers, e-mail en andere applicaties, afhankelijk zijn van realtime interactie. Voor veel aspecten van het spel, zoals de toetsaanslagen van de gebruiker en de positie van de spelers in het spel, maakt het niet uit wat er een seconde geleden is gebeurd, maar alleen de meest actuele stand van zaken in de spelwereld.

Laten we eens kijken naar een eenvoudig voorbeeld van een multiplayergame, zoals een 3D-shooter. Het netwerkgedeelte van het spel is heel eenvoudig opgebouwd: bij elke iteratie van de spelcyclus stuurt de client een beschrijving van alle acties van de speler naar de server (ingedrukte toetsen, muispositie, enz.), en bij elke iteratie verwerkt de server deze gegevens , werkt het model van de spelwereld bij en stuurt de huidige terug naar de clientposities van wereldobjecten, zodat het een nieuw frame voor de speler tekent.

Dus als in ons spel een pakket verloren gaat terwijl het via het netwerk wordt verzonden, stopt het spel en wacht totdat het pakket opnieuw wordt afgeleverd. Aan de clientzijde bevriezen spelobjecten en aan de server kunnen spelers ook niet bewegen of schieten omdat de server geen nieuwe pakketten kan accepteren. Wanneer het verloren pakket uiteindelijk arriveert, bevat het verouderde informatie die niet langer relevant is. Bovendien arriveren hierna ook al die pakketten die zich tijdens de wachttijd in de wachtrij hebben verzameld, en ze moeten allemaal in één iteratie van de lus worden verwerkt. Volledige verwarring!

Helaas is er geen manier om dit gedrag van TCP te veranderen, en dat is ook niet nodig, aangezien dit de betekenis van TCP is. Dit is een noodzaak om van datatransmissie via internet een betrouwbare en consistente datastroom te maken.
Maar we hebben geen betrouwbare en consistente datastroom nodig.

We hebben de gegevens nodig om zo snel mogelijk van de client naar de server te komen, en we willen niet wachten tot de gegevens opnieuw worden verzonden.
Dit is de reden waarom je TCP nooit moet gebruiken voor multiplayer-spellen.

Maar wacht! Waarom kan ik UDP en TCP niet samen gebruiken?

Voor real-time gamegegevens, zoals klikken van gebruikers en de staat van de gamewereld, zijn alleen de meest actuele gegevens belangrijk, maar voor andere soorten gegevens, zoals reeksen opdrachten die van de ene computer naar de andere worden verzonden, is de betrouwbaarheid en consistentie van het kanaal kan heel belangrijk zijn.

Natuurlijk is het verleidelijk om UDP te gebruiken voor gebruikersinvoer en wereldstatusgegevens, en TCP voor gegevens waarvan gegarandeerd moet worden dat ze worden afgeleverd. Je denkt misschien zelfs dat je meerdere ‘threads’ met opdrachten kunt maken, bijvoorbeeld één voor laadniveaus en een andere voor AI-opdrachten. Je denkt: "Ik heb geen AI-teams nodig die in de rij staan ​​te wachten als het datapakket om een ​​niveau te laden verloren gaat, omdat ze totaal niets met elkaar te maken hebben!" In dit geval heeft u gelijk en kunt u besluiten om voor elke opdrachtstroom een ​​TCP-socket te maken.

Op het eerste gezicht is dit een geweldig idee. Maar het probleem is dat, aangezien TCP en UDP beide bovenop IP draaien, de pakketten van beide protocollen elkaar zullen beïnvloeden - al op IP-niveau. Hoe dit effect zich precies zal manifesteren is een zeer complexe vraag, en houdt verband met de betrouwbaarheidsmechanismen in TCP. Maar houd er in ieder geval rekening mee dat het gebruik van TCP meestal leidt tot meer UDP-pakketverlies. Als je hier meer over wilt weten, kun je lezen