Andmete usaldusväärse edastamise alused

Andmete usaldusväärse edastamise alused

Neile, kes püüab soovivad mõista võrgustikke ja protokolle, on pühendatud.

Lühidalt

Artiklis käsitletakse andmete usaldusväärse edastamise aluseid, tuuakse näiteid Go, sealhulgas UDP ja TCP. Inspireerituna üks, kaks, kolmest ja raamatust "Arvutivõrgud. Ülemineku lähenemine", kuna kõik räägivad ainult Tanenbaumist ja Oliferist.

Transpordiprotocol

Tagab loogilise ühenduse erinevates hostides toimivate rakendusprotsesside vahel. Rakenduste seisukohalt näeb loogiline ühendus välja nagu kanal, mis ühendab protsessid otse.

Andmete usaldusväärse edastamise alused

Transpordiprotokollid on toetatud lõpp-süsteemide poolt, kuid mitte võrgu marsruuterite poolt (välja arvatud — DPI). Saatja poolel muundab transpordikiht rakendustaseme andmed, mille ta saab edastamise rakenduse protsessilt, transporditaseme pakettideks, mida nimetatakse segmentideks.

Andmete usaldusväärse edastamise alused

See toimub rakendustaseme sõnumite vajadusel killustamise ja igale neist transporditaseme päise lisamise kaudu.

Andmete usaldusväärse edastamise alused

Seejärel edastab transpordikiht segmendi saatja võrgu kihile, kus segment kapseldatakse võrgu taseme paketti (datagrammi) ja saadetakse välja. Vastuvõtva poole võrgu kiht ekstraktib transporditaseme segmendi datagrammist ja edastab selle üles transporditasemele. Edasi töötleb transpordikiht saadud segmenti nii, et selle andmed muutuvad vastuvõtvale rakendusele kergesti kätte saadavaks.

Andmete usaldusväärse edastamise alused

Usaldusväärse andmeedastuse põhimõtted

Usaldusväärne andmeedastus täiesti usaldusväärses kanal

Lihtsaim juhtum. Saatja poolel võetakse andmed ülalt, luuakse nendes sisalduv pakett ja saadetakse see 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)
    }

    // Loo sokkel porti jaoks
    serverConn, err := net.ListenUDP("udp", serverAddr)
    if err != nil {
        log.Fatal(err)
    }
    // Edasi lükatud ühenduse sulgemine
    defer serverConn.Close()

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

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

Kliendi

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)
    }
    // Edasi lükatud ühenduse sulgemine
    defer conn.Close()

    for {
        // Andmete saamine ÜLSEMISKIHTILT
        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)
        }
        // Üks sekund
        time.Sleep(time.Second * 1)
    }
}

Usaldusväärne andmete edastus kanalilt, kus võivad esineda vead

Järgmine etapp on eeldus, et kõik edastatud paketid on saadud selles järjekorras, milles need saadeti, kuid nendes olevad bitid võivad olla kahjustatud, kuna kanal edastab andmeid mõnikord moonutustega.

Andmete usaldusväärse edastamise alused

Sellisel juhul rakendatakse mehhanisme:

  • vea avastamine;
  • tagasiside;
  • uuesti edastus.

Usaldusväärsete andmete edastusprotokollid, mis sisaldavad sarnaseid korduva edastuse mehhanisme, nimetatakse automaatse kordusnõude (Automatic Repeat reQuest, ARQ) protokollideks.
Lisaks tuleks ette näha ka vigu ja vastuvõtjate kviitungites, kui vastuvõtja ei saa teavet viimase paketi edastamise tulemuste kohta.
Selle ülesande lahendus, mida kasutatakse ka TCP-s, seisneb andmepaketti uue välja lisamises, mis sisaldab paketi järjestuse numbrit.

Andmete usaldusväärse edastamise alused

Usaldusväärne andmete edastus usaldamatul kanalil, mis võimaldab moonutusi ja pakettide kadumist.

Kahjuks esinevad võrgu jooksul ka moonutused ja pakettide kaotus.
Ja selle probleemi lahendamiseks on vajalikud mehhanismid:

  • pakettide kaotuse tuvastamine;
  • kaotatud pakettide uuesti saatmine vastuvõtjale.

Lisaks pakettide kadumisele tuleb arvestada ka kinnituste kadumise võimalusega või, kui mitte midagi ei ole kadunud, selle edastamisega märkimisväärse viivitusega. Igale juhtumile järgneb sama tegevus: paketi kordussaatmine. Selle mehhanismi aja jälgimiseks kasutatakse tagasikutsumise taimerit, mis võimaldab määrata ooteintervalli lõppu. Nii et pakettides net on TCPKeepAlive parameeter vaikimisi seatud 15 sekundiks:

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

Saatja peab käivitama taimeri iga kord paketi edastamisel (nii esmakordsel kui ka kordussaatmisel), töötlema taimerist saadud katkestusi ning peatama selle.

Nii oleme tutvunud usaldusväärse andmeedastuse protokollide põhikontseptsioonidega:

  • kontrollsummad;
  • pakettide järjekorranumbrid;
  • taimerid;
  • positiivsed ja negatiivsed kinnitused.

Aga see ei ole kõik!

Usaldusväärse andmeedastuse protokoll koos konveierimisega.

Käesolevas variandis, mida oleme juba vaadanud, on usaldusväärse edastamise protokoll väga ebatõhus. See hakkab viivitama edastust, mida toetab sidekanal, kui RTT suureneb. Selle tõhususe suurendamiseks ja sidekanali läbilaskevõime parema kasutuse jaoks rakendatakse konveierimist.

Andmete usaldusväärse edastamise alused

Konveierimise rakendamine toob kaasa:

  • järjekorranumbrite piirkonna suurenemine, kuna kõik saadetavad paketid (välja arvatud korduvad edastused) peavad olema selgelt tuvastatavad;
  • vajaduse suurendada mälupuhvrite mahtu saatja ja vastuvõtja poolel.

Järjekorranumbrite vahemik ja mälupuhvrite suuruse nõuded sõltuvad protokolli tegevustest vastusena moonutusele, pakettide kadumisele ja viivitusele. Konveierimise puhul on kaks vigade parandamise meetodit:

  • tagasi N paketti;
  • valikuline kordus.

Tagasi N paketti — libiseva akna protokoll.

Andmete usaldusväärse edastamise alused

Saatjal peab olema kolm tüüpi sündmusi:

  • kõrgema taseme protokolli kutse. Kui "ülemine" tasand kutsub andmete saatmise funktsiooni, kontrollib saatja esmalt akna täituvust (st kas on olemas N saadetud sõnumit, mis ootavad kinnitusi). Kui aken ei ole täidetud, vormitakse ja edastatakse uus pakk, ning muutujate väärtused uuendatakse. Vastupidisel juhul tagastab saatja andmed ülemisele tasandile, mis on kaudne märk, et aken on täidetud. Tüüpiliselt ülemine tasand proovib andmete edastamist uuesti mõne aja pärast. Reaalses rakenduses oleks saatja tõenäoliselt kas andmeid vahemällu salvestanud (mitte kohe saatnud) või omanud sünkroniseerimise mehhanismi (näiteks semafori või lipu), mis võimaldaks ülemisel tasandil kutsuda andmete saatmise funktsiooni vaid siis, kui aken on tühi.
  • kinnituse saamine. Protokollis antakse pakett, mille järjestuse number on N, üldine kinnitus, mis näitab, et kõik pakettide järjestuse numbrid, mis on ettepoole N, on edukalt vastu võetud.
  • ootamisintervalli aegumine. Pakettide ja kinnituste kaotuste ning viivituste tuvastamiseks kasutab protokoll ajastusmeetrit. Kui ootamisintervall aegub, saadab saatja uuesti kõik saadetud kinnitamata paketid.

Valikuline kordamine

Kui akna suurus ja läbilaskevõime korrutatud leviaeg on suured, võib torus olla palju pakette. Sellisel juhul võib ühe paketi tõrge põhjustada paljude pakettide korduvate edastamiste, millest enamus ei olnud vajalikud.

Näide

Parimad teoreetilised praktikad on kokku kogutud praktilises rakendamises TCP. Ja kui keegi teab, kuidas paremini — tere tulemast.

Server

package main

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

func main() {
    // loome soketi sadama 
    ln, err := net.Listen("tcp", ":8081")
    if err != nil {
        log.Fatalln(err)
    }
    // ootame kutset
    conn, _ := ln.Accept()

    for {
        // andmete lugemine
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // sõnumi väljund stdoutisse
        fmt.Print("Sõnum vastu võetud:", string(msg))
        // rea teisendamine suurte tähtedega
        newMsg := strings.ToUpper(msg)
        // andmete saatmine
        conn.Write([]byte(newMsg + "n"))
    }
}

Kliendi

pakett põhjas

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

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

    for {
        // andmete lugemine stdin'ist
        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Saadetav tekst: ")
        // realt
        text, err := reader.ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // saatmine
        fmt.Fprintf(conn, text+"n")
        // vastuvõtt
        msg, err := bufio.NewReader(conn).ReadString('n')
        if err != nil {
            log.Fatalln(err)
        }
        // saadud vastuse kuvamine
        fmt.Print("Serverilt sõnum: " + msg)
    }
}

Kokkuvõte

Mehhanismid, mis tagavad usaldusväärse andme edastamise ja nende kasutamise

Mehhanism
Rakendus, kommentaar

Kontrollsumma
Kasutatakse edastatud paketi bitivigade tuvastamiseks

Taimer
Ooteintervalli mõõtmine ja selle lõppemise näitamine. Viimane tähendab, et suure tõenäosusega on pakk või selle kinnitamine edastamisel kaotsi läinud. Kui pakk saabub viivitusega, kuid mitte kaduma (enneaegne ooteintervalli lõppemine), või toimub kinnitamise kadu, toob uuesti edastamine kaasa pakettide dubleerimise vastuvõtva poolel

Järjekorranumber
Kasutatakse andmepakettide järjekorranumbrite numeerimiseks, mis edastatakse saatjalt vastuvõtjale. Puudujäägid saadud pakettide järjekorranumbris võimaldavad vastuvõtjal tuvastada pakettide kadumise. Sama järjekorranumber tähendab, et paketid dubleerivad üksteist

Kinnitamine
Genereeritakse vastuvõtva poole poolt ja näitab edastava poolele, et vastav pakk või pakettide rühm on edukalt vastu võetud. Reeglina sisaldab kinnitamine edukalt vastu võetud pakettide järjekorranumbrid. Olenevalt protokollist eristatakse individuaalseid ja grupi kinnitusi

Negatiivne kinnitamine
Kasutakse vastuvõtja poolt saatjale teate edastamiseks, et pakk on saadud valesti. Negatiivne kinnitamine sisaldab tavaliselt järjekorranumbrit paketti, mis ei ole korrektselt saadud

Aken, konveierimine
Piiravad kindlate järjekorranumbrite vahemikku, mida saab pakkide edastamiseks kasutada. Grupiedastus ja käepigistus võimaldavad protokollide läbilaskevõimet märkimisväärselt suurendada võrreldes kinnituste ootamisrežiimiga. Nagu me näeme, saab akna suurust arvutada vastuvõtja poole vastuvõtu- ja vahemäluvõimekuse ning võrgu koormuse taseme põhjal.

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

Uues hoidlad.

Allikas: habr.com

Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid 🔥 Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid - ProHoster