Grunderna för pÄlitlig datatransmission

Grunderna för pÄlitlig datatransmission

Till dem som strÀvar vill förstÄ nÀtverk och protokoll.

Kortfattat

Denna artikel behandlar grunderna för sÀker datatransmission och tillhandahÄller exempel pÄ Go, inklusive UDP och TCP. Inspirerat av ett, tvÄ, tre och boken "Computer Networks. Nedtill upp-ansats", eftersom alla bara diskuterar Tanenbaum och Olifer.

Transportprotokoll

Ger en logisk anslutning mellan applikationsprocesser som körs pÄ olika vÀrdar. En logisk anslutning, frÄn applikationernas perspektiv, framstÄr som en kanal som direkt kopplar samman processerna.

Grunderna för pÄlitlig datatransmission

Transportprotokoll underhĂ„lls av slutliga system men inte av nĂ€tverksroutrar (utom — DPI). PĂ„ avsĂ€ndarsidan omvandlar transportlagret de applikationsdata som mottas frĂ„n den skickande applikationsprocessen till transportnivĂ„paket, kallade segment.

Grunderna för pÄlitlig datatransmission

Detta görs genom att dela upp (vid behov) applikationsmeddelanden i fragment och lÀgga till en transportlagersrubrik till varje.

Grunderna för pÄlitlig datatransmission

DÀrefter överför transportlagret segmentet till avsÀndarens nÀtverksnivÄ, dÀr segmentet inkapslas i ett nÀtverksnivÄpaket (datagram) och skickas. PÄ mottagarsidan hÀmtar nÀtverksnivÄn transportlagssegmentet frÄn datagrammet och överför det uppÄt till transportlagret. Sedan bearbetar transportlagret det mottagna segmentet sÄ att dess data blir tillgÀngliga för mottagarens applikation.

Grunderna för pÄlitlig datatransmission

Principer för sÀker datatransmission

SÀker datatransmission över en helt pÄlitlig kanal

Det enklaste fallet. AvsÀndarsidan tar helt enkelt emot data frÄn övre lagret, skapar ett paket som innehÄller dem och skickar det genom kanalen.

Servern

package main

import (
    "log"
    "net"
)

func main() {
    \\ Serverns IP-adress och port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }

    \\ Skapa en socket med porten
    serverConn, err := net.ListenUDP("udp", serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    \\ Fördröjd stÀngning av anslutningen
    defer serverConn.Close()

    \\ Skapa en buffert för data
    buf := make([]byte, 1024)

    \\ VÀnta pÄ anslutning
    for {
        \\ LÀs förfrÄgan
        n, addr, err := serverConn.ReadFromUDP(buf)
        \\ Skicka data till ÖVRE nivĂ„n: i vĂ„rt fall stdout
        println(string(buf[0:n]), " form ", addr.IP.String())
        if err != nil {
            log.Fatal(err)
        }
        \\ Det finns inget svar eftersom det Àr UDP + en pÄlitlig kanal
    }
}

Klient

package main

import (
    "fmt"
    "log"
    "net"
    "time"
)

func main() {
    \\ Serverns IP-adress och port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }
    \\ Lokal IP-adress och port
    localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    if err != nil {
        log.Fatal(err)
    }
    \\ StÀll in anslutning
    conn, err := net.DialUDP("udp", localAddr, serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    \\ Fördröjd stÀngning av anslutningen
    defer conn.Close()

    for {
        \\ Ta emot data frĂ„n ÖVRE nivĂ„n
        fmt.Print("Ange en fras > ")
        var msg string
        _, err := fmt.Scanf("%s", &msg)
        if err != nil {
            log.Fatal(err)
        }
        \\ Ström av bytes skickas, inte strÀng
        buf := []byte(msg)
        \\ Skriv (skicka) till anslutningen
        _, err = conn.Write(buf)
        if err != nil {
            log.Fatal(err)
        }
        \\ VĂ€nta en sekund
        time.Sleep(time.Second * 1)
    }
}

PÄlitlig dataöverföring över en kanal med potentiella fel

NÀsta steg Àr att anta att alla sÀnda paket har mottagits i den ordning de skickades, men bitarna kan vara skadade, eftersom kanalen ibland överför data med förvrÀngningar.

Grunderna för pÄlitlig datatransmission

I sÄdana fall tillÀmpas mekanismer:

  • felupptĂ€ckning;
  • Ă„terkoppling;
  • Ă„teröverföring.

Protokoll för pÄlitlig dataöverföring, som har sÄdana mekanismer för upprepning av överföring, kallas protokoll med automatisk begÀran om Äteröverföring (Automatic Repeat reQuest, ARQ).
Dessutom bör man beakta möjligheten för fel i kvittenserna, nÀr mottagarsidan inte fÄr nÄgon information om resultatet av överföringen av det senaste paketet.
Lösningen pÄ denna uppgift, som Àven anvÀnds i TCP, Àr att lÀgga till ett nytt fÀlt med paketdata som innehÄller sekvensnummer för paketet.

Grunderna för pÄlitlig datatransmission

Tillförlitlig dataöverföring över en opÄlitlig kanal som kan orsaka förvrÀngning och paketförlust

TyvÀrr förekommer paketförlust i nÀtverket samtidigt som förvrÀngningar.
Och för att lösa detta problem krÀvs mekanismer:

  • för att identifiera paketförlust;
  • Ă„terleverans av förlorade paket till mottagarsidan.

Utöver paketförlusten mÄste man Àven övervÀga möjligheten av kvittotabort, eller om inget har förlorats, att kvittot levereras med betydande fördröjning. I alla fall görs samma sak: paketet sÀnds om. För att kontrollera tiden i denna mekanism anvÀnds en nedrÀknare som möjliggör att faststÀlla slutet av vÀntetiden. SÄ i paketet net Àr TCPKeepAlive-parametern som standard instÀlld pÄ 15 sekunder:

// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
    defaultTCPKeepAlive = 15 * time.Second
)

AvsÀndarsidan mÄste starta nedrÀknaren varje gÄng ett paket sÀnds (bÄde vid första och Äterleverans), hantera avbrott frÄn nedrÀknaren och stoppa den.

SÄ vi har blivit bekanta med de viktigaste begreppen för protokoll för pÄlitlig dataöverföring:

  • kontrollsummor;
  • paketordningsnummer;
  • timers;
  • positiva och negativa kvitton.

Men det Àr inte allt!

Protokoll för pÄlitlig dataöverföring med pipelining

I det alternativ som vi redan har granskat Àr protokollet för pÄlitlig leverans mycket ineffektivt. Det börjar "sakta ner" överföringen som tillhandahÄlls av kommunikationskanalen nÀr RTT ökar. För att öka effektiviteten och bÀttre utnyttja bandbredden i kommunikationskanalen anvÀnds pipelining.

Grunderna för pÄlitlig datatransmission

AnvÀndning av pipelining leder till:

  • ökat intervall för paketordningsnummer, eftersom alla skickade paket (utom Ă„terlevererade) mĂ„ste kunna identifieras entydigt;
  • behovet av att öka buffrar pĂ„ sĂ€ndande och mottagande sida.

Intervall för paketordningsnummer och krav pÄ bufferstorlekar beror pÄ de ÄtgÀrder som protokollet vidtar som svar pÄ förvrÀngning, pakettapp och paketfördröjning. Vid pipelining finns det tvÄ metoder för felkorrigering:

  • Ă„tergĂ„ng av N paket tillbaka;
  • urval av upprepning.

ÅtervĂ€ndande av N paket tillbaka — glidande fönsterprotokoll

Grunderna för pÄlitlig datatransmission

AvsÀndaren mÄste stödja tre typer av hÀndelser:

  • anrop till ett protokoll av högre nivĂ„. NĂ€r funktionen för att skicka data anropas "uppifrĂ„n", kontrollerar den sĂ€ndande sidan först hur mycket utrymme som finns i fönstret (det vill sĂ€ga om N meddelanden har skickats och vĂ€ntar pĂ„ bekrĂ€ftelser). Om fönstret inte Ă€r fullt, bildas ett nytt paket och sĂ€nds, och variablerna uppdateras. Annars returnerar den sĂ€ndande sidan datan till den högre nivĂ„n, vilket Ă€r en tyst indikation pĂ„ att fönstret Ă€r fullt. Vanligtvis gör den högre nivĂ„n ett nytt försök att skicka data efter en tid. I en verklig applikation skulle avsĂ€ndaren sannolikt antingen buffra data (istĂ€llet för att direkt skicka dem) eller ha en synkroniseringsmekanism (till exempel en semafor eller flagga) som tillĂ„ter den högre nivĂ„n att anropa funktionen för att skicka data endast nĂ€r fönstret inte Ă€r fullt.
  • mottagande av bekrĂ€ftelse. I protokollet utfĂ€rdas en gemensam bekrĂ€ftelse för paketet med nummer N, som anger att alla paket med nummers som föregĂ„r N har tagits emot framgĂ„ngsrikt.
  • timeout. För att faststĂ€lla förluster och fördröjningar av paket och bekrĂ€ftelser anvĂ€nder protokollet en timer. Om timeouten intrĂ€ffar skickar den sĂ€ndande sidan om alla skickade, obekrĂ€ftade paket.

selektivt ÄterutsÀndande

NÀr fönstrets storlek och produkten av bandbredd och spridningsfördröjning Àr stora, kan det finnas mÄnga paket i rörledningen. I ett sÄdant fall kan felet hos ett enskilt paket orsaka ÄterutsÀndning av mÄnga paket, varav de flesta inte behövdes.

Exempel

BĂ€sta teoretiska metoder samlas i praktisk tillĂ€mpning TCP. Och om nĂ„gon vet hur man gör det bĂ€ttre — vĂ€lkommen.

Servern

package main

import (
    "bufio"
    "fmt"
    "log"
    "net"
    "strings"
)

func main() {
    // skapa en socket med port
    ln, err := net.Listen("tcp", ":8081")
    if err != nil {
        log.Fatalln(err)
    }
    // vÀnta pÄ anrop
    conn, _ := ln.Accept()

    for {
        // lÀsa data
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // skriva meddelande till stdout
        fmt.Print("Meddelande mottaget:", string(msg))
        // göra meddelandet till versaler
        newMsg := strings.ToUpper(msg)
        // skicka data
        conn.Write([]byte(newMsg + "n"))
    }
}

Klient

paket huvud

import (
    "bufio"
    "fmt"
    "log"
    "net"
    "os"
)

func huvud() {
    	// etablera anslutning
    conn, err := net.Dial("tcp", "127.0.0.1:8081")
    if err != nil {
        log.Fatalln(err)
    }

    for {
        	// lÀsa data frÄn stdin
        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text att skicka: ")
        	// rad för rad
        text, err := reader.ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        	// skicka
        fmt.Fprintf(conn, text+"n")
        	// ta emot
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        	// skriv ut det mottagna svaret
        fmt.Print("Meddelande frÄn server: " + msg)
    }
}

Utdata

Mekanismer som sÀkerstÀller pÄlitlig datatransmission och dess anvÀndning

Mekanismen
TillÀmpning, kommentar

Kontrollsumma
AnvÀnds för att upptÀcka bitfel i det överförda paketet

Timer
NedrÀkning av tidsintervallet och indikation pÄ dess utgÄng. Detta innebÀr att paketet eller dess bekrÀftelse sannolikt har gÄtt förlorad under överföringen. Om paketet levereras med fördröjning, men inte gÄr förlorat (för tidig tidsutgÄng), eller om bekrÀftelsen gÄr förlorad, resulterar en omöverföring i en duplicering av paketet pÄ mottagarens sida.

Sekvensnummer
AnvÀnds för sekventiell numrering av datapaket som överförs frÄn avsÀndare till mottagare. HÄl i sekvensnumren pÄ de mottagna paketen gör att mottagaren kan upptÀcka paketförlust. Duplicerade sekvensnummer av paket indikerar att paketen dupliceras.

BekrÀftelse
Genereras av mottagarsidan och anger till avsÀndarsidan att det aktuella paketet eller paketgrupp har mottagits framgÄngsrikt. BekrÀftelsen innehÄller vanligtvis sekvensnummer för de framgÄngsrikt mottagna paketen. Beroende pÄ protokollet sÀrskiljs individuella och grupperade bekrÀftelser.

Negativ bekrÀftelse
AnvÀnds av mottagaren för att meddela avsÀndaren att paketet har mottagits felaktigt. Den negativa bekrÀftelsen inkluderar vanligtvis sekvensnumret för det paket som inte har mottagits korrekt.

Fönster, pipelining
BegrÀnsar intervallet av ordningsnummer som kan anvÀndas för att överföra paket. Gruppenöverföring och handskakning gör det möjligt att avsevÀrt öka protokollens bandbredd jÀmfört med lÀget avvaktan pÄ bekrÀftelser. Som vi kommer att se kan fönsterstorleken berÀknas baserat pÄ mottagarens mottagnings- och buffringskapacitet samt nÀtverksbelastningen.

Andra exempel pÄ att anvÀnda Go för nÀtverksarbete.

I förrÄdet.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster