Usaldusväärse andmeedastuse alused

Usaldusväärse andmeedastuse alused

Neile, kes püüdleb soovivad aru saada võrkudest ja protokollidest, on see pühendatud.

Lühidalt

Artiklis käsitletakse usaldusväärse andmeedastuse aluseid, tuues näiteid Go, sealhulgas UDP ja TCP kohta. Inspireeritud kord, kaks, kolm ja raamatust "Arvutivõrgud. Allavoolu lähenemine", sest kõik räägivad ainult Tanenbaumist ja Oliferist.

Transportprotokoll

tagab loogilise ühenduse rakendusprotsesside vahel, mis töötavad erinevates hostides. Rakenduseste jaoks näeb loogiline ühendus välja nagu kanal, mis ühendab protsessid otse.

Usaldusväärse andmeedastuse alused

Transportprotokolle toetavad lõpp-süsteemid, kuid mitte võrgu marsruutorid (välja arvatud — DPI). Saatja poolel muundab transporttase andmed rakendusastmest, mille ta saab edastavalt rakendusprotsessilt, transporttaseme pakettideks, mida nimetatakse segmentideks.

Usaldusväärse andmeedastuse alused

See toimub rakendusastme sõnumite vajadusel fragmenteerimise ja igaühe juurde transporttaseme päise lisamisega.

Usaldusväärse andmeedastuse alused

Seejärel edastab transporttase segmenti saatja võrgu tasandile, kus segment kapseldatakse võrgu tasandi paketti (datagrammi) ja saadetakse edasi. Vastuvõtva poole võrgu tase ekstraktsioonib transporttase segment datagrammist ja edastab selle üles transporttase. Edasi töötleb transporttase saadud segmenti nii, et selle andmed oleksid vastuvõtva rakenduse jaoks kergesti kättesaadavad.

Usaldusväärse andmeedastuse alused

Andmete usaldusväärse edastamise põhimõtted

Usaldusväärne andmete edastamine täiesti usaldusväärses kanalites

Lihtsaim juhtum. Saatja pool lihtsalt võtab andmed ülemiselt tasandilt, loob neid sisaldava paketi ja saadab selle kanalisse.

Server

package main

import (
    "log"
    "net"
)

func main() {
    // Serveri IP-aadress ja port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }

    // Loome soketi koos portiga
    serverConn, err := net.ListenUDP("udp", serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // Lükatakse ühenduse sulgemine edasi
    defer serverConn.Close()

    // Loome andmepuud
    buf := make([]byte, 1024)

    // Ootame ühendust
    for {
        // Loeme päringu
        n, addr, err := serverConn.ReadFromUDP(buf)
        // Edastame andmed ÜLEMINEKUKIHILE: meie puhul stdout
        println(string(buf[0:n]), " form ", addr.IP.String())
        if err != nil {
            log.Fatal(err)
        }
        // Vastust ei ole, kuna see on UDP + usaldusväärne kanal
    }
}

Klient

package main

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

func main() {
    // Serveri IP-aadress ja port
    serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
    if err != nil {
        log.Fatal(err)
    }
    // Kohalik IP-aadress ja port
    localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    if err != nil {
        log.Fatal(err)
    }
    // Ühenduse loomine
    conn, err := net.DialUDP("udp", localAddr, serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // Ühenduse viivitamine sulgemine
    defer conn.Close()

    for {
        // Andmete vastuvõtt ÜLEMINEKUTEST
        fmt.Print("Sisestage lause > ")
        var msg string
        _, err := fmt.Scanf("%s", &msg)
        if err != nil {
            log.Fatal(err)
        }
        // Edastatakse baitide voog, mitte string
        buf := []byte(msg)
        // Kirjutamine (edastamine) ühendusse
        _, err = conn.Write(buf)
        if err != nil {
            log.Fatal(err)
        }
        // Ootame natuke
        time.Sleep(time.Second * 1)
    }
}

Usaldusväärne andmeedastus kanalil, kus võivad esineda vead

Järgmine etapp on eeldamine, et kõik edastatud paketid on saadud selles järjestuses, milles need saadeti, kuid nende bitid võivad olla kahjustatud, kuna kanalis edastatakse mõnikord andmeid moonutatult.

Usaldusväärse andmeedastuse alused

Sellisel juhul rakendatakse mehhanisme:

  • vea tuvastamine;
  • tagasiside;
  • uuesti edastamine.

Usaldusväärse andmeedastuse protokollid, mis omavad sarnaseid mehhanisme andmeedastuse korduvaks taotlemiseks, nimetatakse automaatse korduvtaotluse protokollideks (Automatic Repeat reQuest, ARQ).
Lisaks tuleks arvestada ka vigade võimalusega kinnitustes, kui vastuvõtja ei saa mingit teavet viimase paketi edastamise tulemuste kohta.
Selle probleemi lahendamiseks, mis on kasutusel ka TCP-s, lisatakse andmepaketti uus väli, mis sisaldab paketi järjestusnumbrit.

Usaldusväärse andmeedastuse alused

Usaldusväärne andmeedastus usaldusväärselt kanali kaudu, mis võimaldab moonutusi ja pakettide kaotust.

Kahjuks kaasnevad moonutustega ka kaotatud paketid.
Ja selle probleemi lahendamiseks vajatakse mehhanisme:

  • pakettide kaotuse määratlemiseks;
  • kaotatud paketide uuesti edastamiseks vastuvõtjale.

Lisaks pakettide kaotusele tuleb arvestada võimalusega kaotada kviitung või, kui midagi ei ole kadunud, selle edastamisega olulise viivitusega. Kõigil juhtudel toimub sama asi: paketi uuesti edastamine. Aja kontrollimiseks kasutatakse selle mehhanismi raames taimerit, mis võimaldab määrata ooteaja lõpu. Nii on pakett. net TCPKeepAlive parameeter on vaikimisi seadistatud 15 sekundiks.

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

Edastaval poolel tuleb iga kord paketi edastamisel (nii esmakordsel kui ka uuesti edastamisel) käivitada taimer, töödelda taimerist tingitud katkestusi ja peatada see.

Nii oleme tutvunud usaldusliku andmeedastuse protokollide põhikontseptsioonidega:

  • kontrollsummadega;
  • pakettide järjestusnumber;
  • taimeritega;
  • positiivsete ja negatiivsete kviitungitega.

Aga see pole veel kõik!

Usaldusliku andmeedastuse protokoll, mis toetab torujuhtmeid.

Selles variandis, mida oleme juba arutanud, on usalduslikkuse transportimise protokoll väga ebatõhus. See hakkab "pidurdama" edastamist, mida pakub sidekanal, RTT suurenedes. Selle tõhususe tõstmiseks ja sidekanali läbilaskvuse parema kasutamise jaoks rakendatakse konveierimist.

Usaldusväärse andmeedastuse alused

Konveierimise rakendamine toob kaasa:

  • järjekorranumbrite arvu suurenemise, kuna kõik saadetavad paketid (kui mitte kordusülekanded) peavad olema üheselt tuvastatavad;
  • vajaduse suurendada puhvermahte edastamise ja vastuvõtmise külgedel.

Järjekorranumbrite vahemik ja puhvermahtude nõudmised sõltuvad protokollist ning sellest, kuidas reageeritakse pärandile, pakettide kadumisele ja viivitusele. Konveierimise puhul on olemas kaks viga parandamise meetodit:

  • tagasivõtmine N paketti tagasi;
  • valikuline kordamine.

Tagasivõtmine N paketti tagasi — libiseva akna protokoll

Usaldusväärse andmeedastuse alused

Saatjal peab olema kolm tüüpi sündmuste jälgimine:

  • ülemise taseme protokolli kutsumine. Kui ülemine tase kutsub üles andmete saatmise funktsiooni, kontrollib saatja esmalt akna täituvust (see tähendab, kas N saadetud sõnumit ootavad vastuvõtu kinnitust). Kui aken on täitmata, moodustatakse ja edastatakse uus pakett ning muutuja väärtused uuendatakse. Vastupidisel juhul edastab saatja andmed ülemisele tasemele, mis on vaikimisi märk sellest, et aken on täidetud. Üldiselt ülemine tase proovib andmete edastamist uuesti pärast mõnda aega. Reaalses rakenduses oleks saatja tõenäoliselt kas andmeid vahemälustanud (asemel koheselt saatmist) või oleks tal sünkroniseerimise mehhanism (nt semafor või lipp), mis võimaldaks ülemisel tasemel funktsiooni kutsuda ainult siis, kui aken on täitmata.
  • kinnitatud vastuvõtmine. Protokollis antakse N järjekorranumbriga paketi kohta üldine kinnituskiri, mis näitab, et kõik pakettide järjekorranumbrid, mis eelnevad N-ile, on edukalt vastu võetud.
  • истечение интервала ожидания. Для определения фактов потерь и задержек пакетов и квитанций протокол использует таймер. Если интервал ожидания истекает, передающая сторона повторно отправляет все посланные неподтвержденные пакеты.

Выборочное повторение

Когда размер окна и произведение пропускной способности на задержку распространения велики, в конвейере может находиться большое количество пакетов. В таком случае ошибка отдельного пакета может вызвать повторную передачу большого количества пакетов, большинство из которых не требовались.

Näide

Лучшие теоритические практики собраны в практической реализации TCP. А если кто-то знает, как лучше — welcome.

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"))
    }
}

Klient

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 {
        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)
    }
}

Kokkuvõte

Mekanismid, mis tagavad usaldusväärse andmete edastamise ja nende kasutamise

Mehhanism
Rakendus, kommentaar

Kontrollsumma
Kasutatakse edastatud paketis bitivigade tuvastamiseks

Taimer
Ooteintervalli loendamine ja selle lõppemise näitamine. Viimane tähendab, et on tõenäoliselt pakett või selle kinnitamine edastamisel kadunud. Kui pakett toimetatakse viivitusega, kuid ei kao (ennatlik ooteintervalli lõpp), või toimub kinnitamise kadumine, siis uue edastamise tulemusel saab saamispoolel paketi dubleerimine.

Järjekorranumber
Kasutatakse andmepakettide järjestikuse numereerimise jaoks, mis edastatakse saatjalt saajale. Saadetud pakettide järjestikusnumbrite katkestused võimaldavad saajal avastada paketi kaotuse. Sama järjestikune number pakettides tähendab, et paketid dubleerivad üksteist.

Kinnitamine
Tegevuspool genereerib, näidates sellele, et vastav pakk või pakkide rühm on edukalt vastu võetud. Tüüpiliselt sisaldab kinnitamine edukalt vastu võetud pakkide järjestikuseid numbreid. Protokollist sõltuvalt eristatakse individuaalseid ja rühmakinnitamisi.

Negatiivne kinnitamine
Kasutatakse saaja poolt saatjale, et teavitada, et pakk on saanud vale. Negatiivne kinnitamine sisaldab tavaliselt paketi järjestikust numbrit, mis ei ole korrektset.

Aken, torustik
Piirab pakettide edastamiseks kasutatavate järjestikuse numbrite vahemikku. Rühmaedastus ja käepigistus võimaldavad märkimisväärselt suurendada protokollide läbilaskevõimet võrreldes kinnituste ooterežiimiga. Nagu näeme, saab akna suurust arvutada vastuvõtva poole vastuvõtu- ja vahemälufunktsioonide ning võrgu koormuse taseme põhjal.

Teised näited Go kasutamisest võrgu tööks

V repositoriis.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster