Základy spoľahlivého prenosu dát

Základy spoľahlivého prenosu dát

Tým, ktorí usiluje sa sa chcú zorientovať v sieťach a protokoloch, je zasvätené.

Stručne

V článku sú preskúmané základy spoľahlivého prenosu dát, realizujú sa príklady na Go, vrátane UDP a TCP. Podľa raz, dva, tri a knihy "Počítačové siete. Zostupný prístup", pretože všetci diskutujú len o Tanenbaumovi a Oliferovi.

Transportný protokol

Zabezpečuje logické spojenie medzi aplikačnými procesmi, ktoré bežia na rôznych hostiteľoch. Z pohľadu aplikácií vyzerá logické spojenie ako kanál, ktorý priamo spája procesy.

Základy spoľahlivého prenosu dát

Transportné protokoly sú podporované koncovými systémami, ale nie sieťovými smerovačmi (okrem - DPI). Na strane odosielateľa transportná úroveň transformuje dáta aplikačnej úrovne, ktoré prijíma od odosielaného aplikačného procesu, na pakety transportnej úrovne nazývané segmenty.

Základy spoľahlivého prenosu dát

To sa dosahuje rozdelením (ak je to potrebné) správ aplikačnej úrovne na fragmenty a pridaním hlavičky transportnej úrovne k každému z nich.

Základy spoľahlivého prenosu dát

Následne transportná úroveň odosiela segment sieťovej úrovni odosielateľa, kde je segment zabalený do paketu sieťovej úrovne (datagramu) a odoslaný. Na prijímajúcej strane sieťová úroveň vyberá segment transportnej úrovne z datagramu a posúva ho smerom nahor na transportnú úroveň. Transportná úroveň potom spracováva prijatý segment tak, aby jeho údaje boli dostupné prijímacej aplikácii.

Základy spoľahlivého prenosu dát

Princípy spoľahlivého prenosu dát

Spoľahlivý prenos dát cez úplne spoľahlivý kanál

Jednoduchý prípad. Odosielajúca strana jednoducho prijíma údaje z horného levelu, vytvára balík, ktorý ich obsahuje, a odosiela ho do kanála.

Server

package main

import (
    "log"
    "net"
)

func main() {
    // IP adresa servera a port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }

    // vytvorenie soketu s portom
    serverConn, err := net.ListenUDP("udp", serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // oneskorené zatvorenie pripojenia
    defer serverConn.Close()

    // vytvorenie buffera pre dáta
    buf := make([]byte, 1024)

    // čakáme na pripojenie
    for {
        // čítame požiadavku
        n, addr, err := serverConn.ReadFromUDP(buf)
        // odosielame dáta na vyššiu úroveň: v našom prípade stdout
        println(string(buf[0:n]), " form ", addr.IP.String())
        if err != nil {
            log.Fatal(err)
        }
        // odpovedať nie je potrebné, keďže ide o UDP + spoľahlivý kanál
    }
}

Klienta

package main

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

func main() {
    // IP adresa servera a port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }
    // miestna IP adresa a port
    localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    if err != nil {
        log.Fatal(err)
    }
    // nadviazanie pripojenia
    conn, err := net.DialUDP("udp", localAddr, serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // oneskorené zatvorenie pripojenia
    defer conn.Close()

    for {
        // získavanie dát z vyššej úrovne
        fmt.Print("Zadajte veta > ")
        var msg string
        _, err := fmt.Scanf("%s", &msg)
        if err != nil {
            log.Fatal(err)
        }
        // odosiela sa prúd bajtov, nie reťazec
        buf := []byte(msg)
        // zápis (odoslanie) do pripojenia
        _, err = conn.Write(buf)
        if err != nil {
            log.Fatal(err)
        }
        // 1 sekunda počkať
        time.Sleep(time.Second * 1)
    }
}

Spoľahlivý prenos dát cez kanál s možnými chybami

Ďalším krokom je predpoklad, že všetky odoslané pakety sú prijaté v tom poradí, v ktorom boli odoslané, avšak bity v nich môžu byť poškodené, pretože kanál občas prenáša dáta s deformáciou.

Základy spoľahlivého prenosu dát

V takomto prípade sú použité mechanizmy:

  • zistenia chýb;
  • spätná väzba;
  • opakovaného odoslania.

Protokoly spoľahlivého prenosu dát, ktoré majú podobné mechanizmy opakovaného prenosu, sa nazývajú protokoly s automatickým žiadosťou o opakovanie prenosu (Automatic Repeat reQuest, ARQ).
Navyše, je potrebné zohľadniť možnosť chýb aj v potvrdeniach, keď prijímajúca strana nedostane žiadne informácie o výsledkoch prenosu posledného paketu.
Riešením tejto úlohy, ktoré sa používa aj v TCP, je pridanie nového poľa do paketu, ktoré obsahuje poradové číslo paketu.

Základy spoľahlivého prenosu dát

Spoľahlivé prenos dát cez nespoľahlivý kanál, ktorý dovoľuje skreslenie a stratu paketov

Žiaľ, popri skresleniach v sieti je prítomná aj strata paketov.
Na vyriešenie tejto úlohy sú potrebné mechanizmy:

  • určenia straty paketov;
  • opätovného zaslania stratenej pakety prijímajúcej strane.

Okrem straty paketu je dôležité zabezpečiť aj možnosť straty potvrdenia alebo, ak nič nebolo stratené, jej doručenie s významným oneskorením. Vo všetkých prípadoch sa vykonáva to isté: opätovný prenos paketu. Na kontrolu času v tomto mechanizme sa používa odpočítavací časovač, ktorý umožňuje určiť koniec čakacej doby. Tak v pakete net parametre TCPKeepAlive sú nastavené na 15 sekúnd ako predvolené:

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

Odosielajúca strana musí spustiť časovač zakaždým pri odoslaní paketu (ako pri prvom, tak aj pri opätovnom), spracovávať prerušenia z časovača a zastaviť ho.

Takže sme sa oboznámili s kľúčovými pojmami protokolov spoľahlivého prenosu dát:

  • kontrolnými súčtami;
  • poradovými číslami paketov;
  • časovačmi;
  • kladnými a zápornými potvrdeniami.

Ale to nie je všetko!

Protokol spoľahlivého prenosu dát s kanbanizáciou

V prípade, ktorý sme už preskúmali, je protokol spoľahlivej dodávky veľmi neefektívny. Pri zvyšovaní RTT začína "zadržiavať" prenos zabezpečený komunikačným kanálom. Na zlepšenie jeho efektivity a lepšie využitie šírky pásma komunikačného kanála sa používa kanbanizácia.

Základy spoľahlivého prenosu dát

Použitie kanbanizácie vedie k:

  • zvýšeniu rozsahu poradových čísel, pretože všetky odoslané pakety (okrem opätovných prenosov) musia byť jednoznačne identifikovateľné;
  • potrebe zvýšiť buffery na odosielajúcej a prijímajúcej strane.

Rozsah poradových čísel a požiadavky na veľkosť bufferov závisia od činov, ktoré protokol podniká v reakcii na skreslenie, stratu a oneskorenie paketu. V prípade kanbanizácie existujú dva spôsoby opravy chýb:

  • návrat o N paketov späť;
  • výberové opakovanie.

Návrat o N paketov späť — protokol kĺzavého okna

Základy spoľahlivého prenosu dát

Odosielateľ musí sledovať tri typy udalostí:

  • volanie protokolom vyššej úrovne. Keď je vyvolaná funkcia na odosielanie údajov, odosielajúca strana najskôr skontroluje úroveň zaplnenia okna (to znamená počet odoslaných správ, ktoré čakajú na potvrdenie). Ak je okno nezaplné, nová správa sa vytvorí a odošle, a hodnoty premenných sa aktualizujú. Inak odosielajúca strana vracia údaje vyššej úrovni, čo je implicitná indikácia, že okno je zaplnené. Zvyčajne sa vyššia úroveň pokúša o opätovné odoslanie údajov po určitom čase. V reálnej aplikácii by odosielateľ pravdepodobne buď vyrovnával údaje (namiesto okamžitého odosielania), alebo mal mechanizmus synchronizácie (napríklad semafor alebo flag), ktorý by umožnil vyššej úrovni vyvolať funkciu na odosielanie údajov len pri nezaplnom okne.
  • potvrdenie prijatia. V protokole pre paket s poradovým číslom N sa vydáva celkové potvrdenie, ktoré indikuje, že všetky pakety s poradovými číslami predchádzajúcimi N boli úspešne prijaté.
  • vypršanie časového limitu. Na určenie strát a oneskorení paketov a potvrdení protokol používa časovač. Ak časový limit vyprší, odosielajúca strana znovu odošle všetky odoslané potvrdzujúce pakety.

vyberané opakovanie

Keď je veľkosť okna a súčin priepustnosti a oneskorenia veľký, v potrubí môže byť veľké množstvo paketov. V takom prípade chyba jedného paketu môže spôsobiť opakované prenášanie veľkého množstva paketov, z ktorých väčšina nebola potrebná.

Príklad

Najlepšie teoretické praktiky sú zozbierané v praktickej realizácii TCP. A ak niekto vie, ako lepšie — vitajte.

Server

package main

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

func main() {
    // vytvoríme soket s portom 
    ln, err := net.Listen("tcp", ":8081")
    if err != nil {
        log.Fatalln(err)
    }
    // čakáme na volanie
    conn, _ := ln.Accept()

    for {
        // čítanie údajov
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // výstup správy do stdout
        fmt.Print("Správa prijatá:", string(msg))
        // premena reťazca na veľké písmená
        newMsg := strings.ToUpper(msg)
        // odosielanie údajov
        conn.Write([]byte(newMsg + "n"))
    }
}

Klienta

package main

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

func main() {
    // nastavenie pripojenia
    conn, err := net.Dial("tcp", "127.0.0.1:8081")
    if err != nil {
        log.Fatalln(err)
    }

    for {
        // čítanie dát z stdin
        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text na odoslanie: ")
        // po riadkoch
        text, err := reader.ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // odoslanie
        fmt.Fprintf(conn, text+"n")
        // prijatie
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // výstup prijatej odpovede
        fmt.Print("Správa zo servera: " + msg)
    }
}

Záver

Mechanizmy zabezpečujúce spoľahlivý prenos dát a ich použitie

Mechanizmus
Použitie, komentár

Kontrolný súčet
Používa sa na odhaľovanie bitových chýb v prenášanom pakete

Časovač
Odpočet časového intervalu a označenie jeho uplynutia. Posledné znamená, že s vysokou pravdepodobnosťou je paket alebo jeho potvrdenie stratené pri prenose. V prípade, že paket je doručený so zdržaním, ale nie je stratený (predčasné uplynutie časového intervalu), alebo dochádza k strate potvrdenia, opakované odoslanie vedie k duplicite paketu na prijímajúcej strane

Poradové číslo
Používa sa na poradovú numeráciu paketov dát prenášaných od odosielateľa k prijímateľovi. Medzery v poradových číslach prijatých paketov umožňujú prijímateľovi odhaliť stratu paketu. Rovnako poradové čísla paketov znamenajú, že pakety sú duplikáty

Potvrdenie
Generuje sa prijímajúcou stranou a označuje odosielajúcej strane, že príslušný paket alebo skupina paketov bola úspešne prijatá. Zvyčajne potvrdenie obsahuje poradové čísla úspešne prijatých paketov. V závislosti od protokolu sa rozlišujú individuálne a skupinové potvrdenia

Negatívne potvrdenie
Používa sa prijímateľom na oznámenie odosielateľovi, že paket bol prijatý nesprávne. Negatívne potvrdenie obvykle zahŕňa poradové číslo paketu, ktorý nebol správne prijatý

Okno, kanálové spracovanie
Obmedzujú rozsah poradových čísel, ktoré môžu byť použité na prenos paketov. Skupinový prenos a handshake umožňujú výrazne zvýšiť priepustnosť protokolov v porovnaní s režimom čakajúceho potvrdenia. Ako uvidíme, veľkosť okna môže byť vypočítaná na základe prijímacích a bufferingových schopností prijímacej strany, ako aj úrovne zaťaženia siete.

Ďalšie príklady využitia Go pri práci so sieťou.

V repozitári.

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster