Usaldusväärse andmeedastuse põhialused

Usaldusväärse andmeedastuse põhialused

Neile, kes otsib Pühendatud võrkude ja protokollide mõistmisele.

Lühidalt

Artiklis käsitletakse usaldusväärse andmeedastuse põhitõdesid, rakendatakse näiteid Go, sealhulgas UDP ja TCP. Põhineb aeg, два, kolm ja raamatud "Arvutivõrgud. Ülalt-alla lähenemine", muidu arutlevad kõik ainult Tannenbaumi ja Oliferovi üle.

Transpordikihi protokoll

Pakub loogilist ühendust erinevatel hostidel töötavate rakendusprotsesside vahel. Rakenduse vaatenurgast näeb loogiline ühendus välja nagu kanal, mis ühendab otseselt protsesse.

Usaldusväärse andmeedastuse põhialused

Transpordikihi protokollid neid toetavad lõppsüsteemid, kuid mitte võrguruuterid (välja arvatud - DPI). Saatja poolel teisendab transpordikiht rakenduskihi andmed, mis ta saab saatvast rakendusprotsessist transpordikihi pakettideks, mida nimetatakse segmentideks.

Usaldusväärse andmeedastuse põhialused

Selleks jagatakse (vajadusel) rakendusekihi sõnumid fragmentideks ja lisatakse igaühele neist transpordikihi päis.

Usaldusväärse andmeedastuse põhialused

Seejärel edastab transpordikiht segmendi saatja võrgukihile, kus segment kapseldatakse võrgukihi paketti (datagrammi) ja saadetakse. Vastuvõtvas otsas eraldab võrgukiht datagrammist transpordikihi segmendi ja edastab selle transpordikihile. Järgmisena töötleb transpordikiht vastuvõetud segmenti nii, et selle andmed muutuvad vastuvõtvale rakendusele kättesaadavaks.

Usaldusväärse andmeedastuse põhialused

Usaldusväärse andmeedastuse põhimõtted

Usaldusväärne andmeedastus täiesti turvalise kanali kaudu

Lihtsaim juhtum. Saatja pool võtab lihtsalt andmed vastu ülemisest kihist, loob neid sisaldava paketi ja saadab kanalile.

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 + надежный канал
    }
}

Klient

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

Usaldusväärne andmeedastus kanali kaudu koos võimalike vigadega

Järgmine samm on eeldada, et kõik edastatud paketid võetakse vastu nende saatmise järjekorras, kuid nendes olevad bitid võivad olla rikutud, kuna kanal edastab mõnikord andmeid moonutustega.

Usaldusväärse andmeedastuse põhialused

Sel juhul kasutatakse järgmisi mehhanisme:

  • vigade tuvastamine;
  • tagasiside;
  • taasedastus.

Usaldusväärseid andmeedastusprotokolle, millel on sarnased mehhanismid edastuse mitmekordseks kordamiseks, nimetatakse automaatse korduspäringu (ARQ) protokollideks.
Lisaks tasub arvestada kviitungite vigade võimalusega, kui vastuvõttev pool ei saa viimase paketi edastamise tulemuste kohta teavet.
Selle probleemi lahendus, mida kasutatakse ka TCP-s, on lisada andmepaketile uus väli, mis sisaldab paketi järjekorranumbrit.

Usaldusväärse andmeedastuse põhialused

Usaldusväärne andmeedastus ebausaldusväärse kanali kaudu, mis võib kahjustada pakettide moonutusi ja kadu

Paraku koos moonutustega on võrgus ka pakettakad.
Ja selle probleemi lahendamiseks on vaja mehhanisme:

  • pakettide kadumise fakti kindlakstegemine;
  • kaotatud pakettide uuesti üleandmine vastuvõtvale poolele.

Lisaks tuleb lisaks paki kaotsiminekule ette näha ka kviitungi kaotamise võimalus või kui midagi kaotsi ei lähe, siis selle kohaletoimetamine olulise hilinemisega. Kõikidel juhtudel tehakse sama: pakett saadetakse uuesti. Aja juhtimiseks kasutab see mehhanism taimerit, mis võimaldab määrata ooteintervalli lõpu. Nii et pakendis neto TCPKeepAlive on vaikimisi seatud 15 sekundile:

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

Saatev pool peab käivitama taimeri iga kord, kui pakett saadetakse (nii esimesel kui ka teisel korral), käsitlema taimeri katkestusi ja peatama selle.

Seega oleme tutvunud usaldusväärsete andmeedastusprotokollide põhimõistetega:

  • kontrollsummad;
  • pakkide järjekorranumbrid;
  • taimerid;
  • positiivsed ja negatiivsed laekumised.

Kuid see pole veel kõik!

Usaldusväärne andmeedastusprotokoll koos torujuhtmetega

Variant, mida me juba kaalusime, on usaldusväärne tarneprotokoll väga ebaefektiivne. See hakkab "aeglustama" sidekanali pakutavat edastamist, kui RTT suureneb. Selle efektiivsuse suurendamiseks ja sidekanali võimsuse paremaks ärakasutamiseks kasutatakse torujuhtmeid.

Usaldusväärse andmeedastuse põhialused

Torujuhtmete kasutamine toob kaasa:

  • järjenumbrite vahemiku suurendamine, kuna kõik saadetud paketid (välja arvatud kordusedastused) peavad olema üheselt identifitseeritud;
  • vajadus suurendada puhvreid saate- ja vastuvõtupoolel.

Järjenumbrite vahemik ja puhvri suuruse nõuded sõltuvad toimingutest, mida protokoll võtab vastuseks pakettide riknemisele, kadumisele ja viivitamisele. Torujuhtmestiku puhul on vigade parandamiseks kaks meetodit:

  • tagastab N paketti tagasi;
  • valikuline kordamine.

Tagasi minnes N paketti – libiseva akna protokoll

Usaldusväärse andmeedastuse põhialused

Saatja peab toetama kolme tüüpi sündmusi:

  • helistada kõrgema taseme protokolli kaudu. Kui andmeedastusfunktsiooni nimetatakse "ülevalt", kontrollib saatja esmalt akna täituvuse astet (st N saadetud sõnumi olemasolu, mis ootavad kviitungi saamist). Kui aken on tühi, genereeritakse ja edastatakse uus pakett ning muutujate väärtusi värskendatakse. Vastasel juhul tagastab saatja andmed ülemisse kihti ja see on kaudne märge, et aken on täis. Tavaliselt proovib ülemine kiht andmeid mõne aja pärast uuesti edastada. Reaalses rakenduses puhverdaks saatja tõenäoliselt andmed (selle asemel et neid kohe saata) või oleks sünkroonimismehhanism (nt semafor või lipp), mis võimaldaks ülemisel kihil kutsuda saatmisfunktsiooni ainult siis, kui aken on tühi. .
  • kinnituse saamine. Protokollis väljastatakse järjekorranumbriga N paketi puhul üldine kinnitus, mis näitab, et kõik paketid, mille järjekorranumbrid on enne N, on edukalt vastu võetud.
  • ooteintervall on möödas. Pakettide ja laekumiste kadumise ja hilinemise faktide kindlakstegemiseks kasutab protokoll taimerit. Kui ajalõpu intervall aegub, saadab saatja kõik saadetud kinnitamata paketid uuesti.

Valikuline kordamine

Kui akna suurus ja läbilaskevõime-leviviivituse korrutis on suured, võib käsil olla suur hulk pakette. Sellisel juhul võib ühe paketi tõrge põhjustada suure hulga pakettide uuesti edastamise, millest enamikku polnud vaja.

Näide

Top teoreetiline praktikaid kogutakse praktilises rakendamises TCP. Ja kui keegi teab, kuidas kõige paremini - teretulnud.

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 {
        // считывание данных с 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)
    }
}

Väljund

Mehhanismid, mis tagavad usaldusväärse andmeedastuse ja kasutamise

Mehhanism
Taotlus, kommentaar

Kontrolli summa
Kasutatakse bitivigade tuvastamiseks edastatud paketis

taimer
Loendab ajalõpu intervalli ja näitab, millal see aegunud on. Viimane tähendab, et suure tõenäosusega läheb pakett või selle vastuvõtmine edastamise ajal kaotsi. Kui pakett tarnitakse hilinemisega, kuid see ei lähe kaduma (ajalõpu intervalli enneaegne aegumine) või kviitung kaob, toob uuesti saatmine vastuvõtval poolel kaasa duplikaatpaketi

Seerianumber
Kasutatakse saatjalt adressaadile edastatavate andmepakettide järjestikuseks nummerdamiseks. Lüngad vastuvõetud pakettide järjenumbrites võimaldavad vastuvõtjal tuvastada pakettide kadumise. Samad pakettide järjenumbrid tähendavad, et paketid on üksteise duplikaadid

Kinnitus
Genereerib vastuvõtuotsa ja näitab saatmisotsale, et vastav pakett või pakettide rühm on edukalt vastu võetud. Tavaliselt sisaldab kinnitus edukalt vastu võetud pakettide järjekorranumbreid. Sõltuvalt protokollist eristatakse individuaalseid ja rühmakinnitusi

Negatiivne kinnitus
Saaja kasutab seda saatja teavitamiseks, et pakett võeti vastu valesti. Negatiivne kinnitus sisaldab tavaliselt valesti vastu võetud paketi järjenumbrit

Aken, konveier
Piirake pakettide edastamiseks kasutatavate järjenumbrite vahemikku. Multisaade ja käepigistus võivad märkimisväärselt suurendada protokolli läbilaskevõimet võrreldes kinnituste ootamisega. Nagu näeme, saab akna suurust arvutada vastuvõtva otsa vastuvõtu- ja puhverdusvõimaluste ning võrgu koormustaseme põhjal

Veel näiteid Go kasutamisest võrgustamiseks

В hoidlad.

Allikas: www.habr.com

Lisa kommentaar