Basisprincipes van betrouwbare gegevensoverdracht

Basisprincipes van betrouwbare gegevensoverdracht

Voor degenen die zoekt Toegewijd aan het begrijpen van netwerken en protocollen.

Kort

In het artikel worden de basisprincipes van betrouwbare gegevensoverdracht besproken en worden voorbeelden hiervan geïmplementeerd. Go, inclusief UDP en TCP. Gebaseerd op tijd, два, drie en het boek "Computer Networks. A Top-Down Approach", verder heeft iedereen het alleen maar over Tannenbaum en Oliferov.

Transportlaagprotocol

Biedt een logische verbinding tussen toepassingsprocessen die op verschillende hosts worden uitgevoerd. Vanuit het perspectief van de applicatie wordt een logische verbinding gezien als een kanaal dat processen rechtstreeks met elkaar verbindt.

Basisprincipes van betrouwbare gegevensoverdracht

Transportlaagprotocollen ondersteund door eindsystemen maar niet door netwerkrouters (behalve - DPI). Aan de verzenderzijde zet de transportlaag de applicatielaaggegevens die het ontvangt van het verzendende applicatieproces om in transportlaagpakketten, zogenaamde segmenten.

Basisprincipes van betrouwbare gegevensoverdracht

Dit wordt gedaan door (indien nodig) applicatielaagberichten op te splitsen in fragmenten en aan elk fragment een transportlaagheader toe te voegen.

Basisprincipes van betrouwbare gegevensoverdracht

De transportlaag geeft het segment vervolgens door aan de netwerklaag van de verzender. Daar wordt het segment ingekapseld in een netwerklaagpakket (datagram) en verzonden. Aan de ontvangende kant extraheert de netwerklaag het transportlaagsegment uit het datagram en geeft dit door aan de transportlaag. Vervolgens verwerkt de transportlaag het ontvangen segment, zodat de gegevens beschikbaar worden voor de ontvangende toepassing.

Basisprincipes van betrouwbare gegevensoverdracht

Principes van veilige gegevensoverdracht

Betrouwbare gegevensoverdracht via een volledig beveiligd kanaal

Het eenvoudigste geval. De verzendende kant ontvangt simpelweg gegevens van de bovenste laag, creëert een pakket met de gegevens en verstuurt deze via het kanaal.

Server

package main

import (
    "log"
    "net"
)

func main() {
    // IP-адрес сервера и порт
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }

    // создаем сокет с портом
    serverConn, err := net.ListenUDP("udp", serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // отложенное закрытие соединения
    defer serverConn.Close()

    // создаем буфер для данных
    buf := make([]byte, 1024)

    // ждем соединение
    for {
        // читаем запрос
        n, addr, err := serverConn.ReadFromUDP(buf)
        // передаем данные в ВЕРХНИЙ уровень: в нашем случае stdout
        println(string(buf[0:n]), " form ", addr.IP.String())
        if err != nil {
            log.Fatal(err)
        }
        // ответа нет, т.к. это UDP + надежный канал
    }
}

klant

package main

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

func main() {
    // IP-адрес сервера и порт
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }
    // локальный IP-адрес и порт
    localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    if err != nil {
        log.Fatal(err)
    }
    // установка соединения
    conn, err := net.DialUDP("udp", localAddr, serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // отложенное закрытие соединения
    defer conn.Close()

    for {
        // получение данных от ВЕРХНЕГО уровня
        fmt.Print("Введите строчное предложение > ")
        var msg string
        _, err := fmt.Scanf("%s", &msg)
        if err != nil {
            log.Fatal(err)
        }
        // передается поток байт, а не строка
        buf := []byte(msg)
        // запись (передача) в соединение
        _, err = conn.Write(buf)
        if err != nil {
            log.Fatal(err)
        }
        // 1 секундочку
        time.Sleep(time.Second * 1)
    }
}

Betrouwbare gegevensoverdracht via een kanaal met mogelijke fouten

De volgende stap is om aan te nemen dat alle verzonden pakketten worden ontvangen in de volgorde waarin ze zijn verzonden. De bits daarin kunnen echter beschadigd zijn omdat het kanaal soms gegevens met vervormingen verzendt.

Basisprincipes van betrouwbare gegevensoverdracht

In dit geval worden de volgende mechanismen toegepast:

  • foutdetectie;
  • feedback;
  • heruitzending.

Betrouwbare gegevensoverdrachtprotocollen die over mechanismen voor meervoudige herhaling van de transmissie beschikken, worden Automatic Repeat reQuest (ARQ)-protocollen genoemd.
Daarnaast moet u rekening houden met mogelijke fouten bij ontvangst, wanneer de ontvangende partij geen informatie ontvangt over de uitkomsten van de overdracht van het laatste pakket.
De oplossing voor dit probleem, dat onder andere in TCP wordt gebruikt, is om een ​​nieuw veld aan het datapakket toe te voegen met daarin het volgnummer van het pakket.

Basisprincipes van betrouwbare gegevensoverdracht

Betrouwbare gegevensoverdracht via een onbetrouwbaar kanaal dat pakketvervorming en -verlies toelaat

Naast verstoringen is er helaas ook sprake van pakketverlies in het netwerk.
Om dit probleem op te lossen, zijn mechanismen nodig:

  • het vaststellen van het feit dat er sprake is van pakketverlies;
  • herlevering van verloren pakketten aan de ontvangende partij.

Naast het verlies van het pakket, moet er bovendien rekening mee gehouden worden dat de bon verloren kan gaan of, als er niets verloren gaat, dat de bezorging met aanzienlijke vertraging kan plaatsvinden. In alle gevallen gebeurt hetzelfde: het pakket wordt opnieuw verzonden. Om de tijd te controleren maakt dit mechanisme gebruik van een afteltimer, waarmee u het einde van de wachttijd kunt bepalen. Dus in het pakket net TCPKeepAlive is standaard ingesteld op 15 seconden:

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

De verzendende kant moet de timer elke keer starten wanneer er een pakket wordt verzonden (zowel de eerste keer als de tweede keer), interrupts van de timer verwerken en de timer stoppen.

We zijn dus bekend met de belangrijkste concepten van betrouwbare gegevensoverdrachtprotocollen:

  • controlesommen;
  • serienummers van pakketten;
  • timers;
  • positieve en negatieve ontvangsten.

Maar dat is nog niet alles!

Betrouwbaar gegevensoverdrachtprotocol met pijplijning

In de versie die we al hebben besproken, is het betrouwbare leveringsprotocol erg inefficiënt. Naarmate RTT toeneemt, begint het de transmissie die via het communicatiekanaal wordt geleverd te "vertragen". Om de efficiëntie te verhogen en de capaciteit van het communicatiekanaal beter te benutten, wordt gebruikgemaakt van pipelining.

Basisprincipes van betrouwbare gegevensoverdracht

Het gebruik van pipelining resulteert in:

  • het vergroten van het bereik van de volgnummers, omdat alle verzonden pakketten (behalve hertransmissies) uniek identificeerbaar moeten zijn;
  • de noodzaak om de buffers aan de zend- en ontvangstzijde te vergroten.

Het bereik van sequentienummers en de vereisten voor de buffergrootte zijn afhankelijk van de acties die het protocol onderneemt als reactie op pakketcorruptie, verlies en vertraging. Bij pipelining zijn er twee methoden voor foutcorrectie:

  • stuur N pakketten terug;
  • selectieve herhaling.

Achterwaartse N-pakketten - schuifvensterprotocol

Basisprincipes van betrouwbare gegevensoverdracht

De verzender moet drie soorten gebeurtenissen ondersteunen:

  • oproep via een protocol op hoger niveau. Wanneer de functie voor het verzenden van gegevens "van bovenaf" wordt aangeroepen, controleert de verzendende zijde eerst in hoeverre het venster is gevuld (dat wil zeggen, de aanwezigheid van N verzonden berichten die wachten op ontvangst). Als het venster niet gevuld is, wordt er een nieuw pakket gevormd en verzonden, en worden de waarden van de variabelen bijgewerkt. Anders stuurt de verzendende kant gegevens terug naar de hogere laag, wat impliciet aangeeft dat het venster vol is. Normaal gesproken probeert de bovenste laag de gegevens na enige tijd opnieuw te verzenden. In een echte toepassing zou de verzender de gegevens waarschijnlijk bufferen (in plaats van ze onmiddellijk te verzenden) of over een synchronisatiemechanisme beschikken (zoals een semafoor of vlag) waarmee de hogere laag de verzendfunctie alleen kan aanroepen wanneer het venster niet vol is.
  • bevestiging ontvangen. In het protocol wordt voor een pakket met sequentienummer N een algemene bevestiging uitgegeven, waarin wordt aangegeven dat alle pakketten met sequentienummers voorafgaand aan N succesvol zijn ontvangen.
  • time-outperiode verlopen. Het protocol maakt gebruik van een timer om verlies en vertragingen van pakketten en ontvangsten te detecteren. Als het time-outinterval verloopt, verstuurt de verzendende partij alle verzonden niet-bevestigde pakketten opnieuw.

Selectieve herhaling

Wanneer de venstergrootte en het doorvoer-vertragingsproduct groot zijn, kan er zich een groot aantal pakketten in de pijplijn bevinden. In zo'n geval kan een fout in één enkel pakket ertoe leiden dat een groot aantal pakketten opnieuw moet worden verzonden, waarvan de meeste niet nodig waren.

Voorbeeld

Top theoretisch praktijken worden verzameld in de praktische implementatie TCP. En als iemand het beter weet - welkom.

Server

package main

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

func main() {
    // создаем сокет с портом 
    ln, err := net.Listen("tcp", ":8081")
    if err != nil {
        log.Fatalln(err)
    }
    // ожидание вызова
    conn, _ := ln.Accept()

    for {
        // считывание данных
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // вывод сообщения в stdout
        fmt.Print("Message Received:", string(msg))
        // перевод строки в верхний регистр
        newMsg := strings.ToUpper(msg)
        // отправка данных
        conn.Write([]byte(newMsg + "n"))
    }
}

klant

package main

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

func main() {
    // установка соединения
    conn, err := net.Dial("tcp", "127.0.0.1:8081")
    if err != nil {
        log.Fatalln(err)
    }

    for {
        // считывание данных с stdin
        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text to send: ")
        // построчно
        text, err := reader.ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // отправка
        fmt.Fprintf(conn, text+"n")
        // прием
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // вывод полученного ответа
        fmt.Print("Msg from Server: " + msg)
    }
}

Uitgang

Mechanismen die een betrouwbare gegevensoverdracht en -gebruik garanderen

mechanisme
Toepassing, commentaar

Controlesom
Wordt gebruikt om bitfouten in een verzonden pakket te detecteren.

Timer
Het aftellen van het time-outinterval en het aangeven van de afloop ervan. Dit laatste betekent dat de kans groot is dat het pakket of het ontvangstbewijs tijdens de verzending verloren is gegaan. Als een pakket te laat wordt afgeleverd maar niet verloren gaat (vroegtijdige afloop van de time-outperiode) of als de ontvangst verloren gaat, resulteert hertransmissie in een duplicaat van het pakket aan de ontvangende kant.

Serienummer
Wordt gebruikt voor de opeenvolgende nummering van datapakketten die van verzender naar ontvanger worden verzonden. Door gaten in de volgnummers van ontvangen pakketten kan de ontvanger pakketverlies detecteren. Identieke volgnummers van pakketten betekenen dat de pakketten duplicaten van elkaar zijn.

Bevestiging
Wordt gegenereerd door de ontvangende partij en geeft aan de verzendende partij aan dat het overeenkomstige pakket of de groep pakketten succesvol is ontvangen. Normaal gesproken bevat de bevestiging de volgnummers van de succesvol ontvangen pakketten. Afhankelijk van het protocol wordt er onderscheid gemaakt tussen individuele en groepsbevestigingen.

Negatieve bevestiging
Wordt door de ontvanger gebruikt om de verzender te informeren dat het pakket onjuist is ontvangen. Een negatieve bevestiging bevat doorgaans het volgnummer van het pakket dat niet correct is ontvangen.

Venster, pijpleiding
Beperk het bereik van sequentienummers die kunnen worden gebruikt om pakketten te verzenden. Multicast- en handshake-transmissies maken een aanzienlijke verhoging van de doorvoersnelheid van protocollen mogelijk vergeleken met de modus waarbij op bevestigingen wordt gewacht. Zoals we zullen zien, kan de venstergrootte worden berekend op basis van de ontvangst- en buffercapaciteiten van de ontvangende kant en de netwerkbelasting.

Meer voorbeelden van Go Networking

В opslagplaatsen.

Bron: www.habr.com

Voeg een reactie