Usaldusväärse andmeedastuse põhialused

Usaldusväärse andmeedastuse põhialused

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

Lühidalt

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

Transpordikihi protokoll

Pakub loogilist ühendust erinevatel hostidel töötavate rakendusprotsesside vahel. Rakenduste vaatenurgast paistab loogiline ühendus protsesse otse ühendava kanalina.

Usaldusväärse andmeedastuse põhialused

Transpordikihi protokollid lõppsüsteemide, aga mitte võrguruuterite poolt toetatud (välja arvatud - DPISaatja poolel teisendab transpordikiht edastavalt rakendusprotsessilt vastuvõetud rakenduskihi andmed transpordikihi pakettideks, mida nimetatakse segmentideks.

Usaldusväärse andmeedastuse põhialused

Seda tehakse rakenduskihi sõnumite (vajadusel) fragmentideks jagamise ja igale neist transpordikihi päise lisamise teel.

Usaldusväärse andmeedastuse põhialused

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

Usaldusväärse andmeedastuse põhialused

Turvalise andmeedastuse põhimõtted

Usaldusväärne andmeedastus täiesti turvalise kanali kaudu

Lihtsaim juhtum: saatja pool lihtsalt võtab ülemiselt kihilt andmeid vastu, loob neid sisaldava paketi ja saadab need kanali kaudu edasi.

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 üle kanali, kus on võimalikud vead

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

Sellisel juhul rakendatakse järgmisi mehhanisme:

  • vigade tuvastamine;
  • tagasiside;
  • taasedastamine.

Usaldusväärseid andmeedastusprotokolle, millel on sellised mehhanismid mitmekordseks edastuskorduseks, nimetatakse automaatseks kordusnõustamiseks (ARQ) protokollideks.
Lisaks tasub kaaluda kviitungite vigade võimalikkust, kui vastuvõttev pool ei saa viimase paketiedastuse tulemuste kohta mingit teavet.
Selle probleemi lahendus, mida kasutatakse muuhulgas TCP-s, on andmepaketti uue välja lisamine, mis sisaldab paketi järjekorranumbrit.

Usaldusväärse andmeedastuse põhialused

Usaldusväärne andmeedastus ebausaldusväärse kanali kaudu, mis võimaldab pakettide moonutamist ja kadumist

Lisaks moonutustele esineb võrgus kahjuks ka pakettide kadu.
Ja selle probleemi lahendamiseks on vaja mehhanisme:

  • pakettide kadumise fakti kindlakstegemine;
  • kadunud pakettide uuesti kättetoimetamine vastuvõtjale.

Lisaks pakettide kadumisele on vaja arvestada ka kviitungi kadumise võimalusega või kui midagi ei kao, siis selle kohaletoimetamisega olulise viivitusega. Kõigil juhtudel toimub sama toiming: pakett saadetakse uuesti. Ajastuse juhtimiseks kasutab see mehhanism taimerit, mis võimaldab määrata ooteintervalli lõppu. Seega paketis neto Vaikimisi on TCPKeepAlive seatud 15 sekundile:

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

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

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

  • kontrollsummad;
  • pakendite seerianumbrid;
  • taimerid;
  • positiivsed ja negatiivsed laekumised.

Aga see pole veel kõik!

Usaldusväärne andmeedastusprotokoll torujuhtmega

Eelnevalt käsitletud rakenduses on usaldusväärne edastusprotokoll väga ebaefektiivne. See hakkab RTT suurenedes sidekanali pakutavat edastust "aeglustama". Selle efektiivsuse parandamiseks ja sidekanali ribalaiuse paremaks ärakasutamiseks kasutatakse torujuhtmetehnoloogiat.

Usaldusväärse andmeedastuse põhialused

Torujuhtmete kasutamine annab tulemuseks:

  • järjekorranumbrite vahemiku suurendamine, kuna kõik saadetud paketid (välja arvatud korduseksdastamised) peavad olema üheselt tuvastatavad;
  • vajadus suurendada saatja ja vastuvõtja puhvreid.

Järjekorranumbrite vahemik ja puhvri suuruse nõuded sõltuvad protokolli reaktsioonist pakettide rikkumisele, kadumisele ja viivitusele. Torujuhtme puhul on kaks veaparandusmeetodit:

  • tagasta N paketti tagasi;
  • valikuline kordamine.

Tagasiulatuvad N paketid - libiseva akna protokoll

Usaldusväärse andmeedastuse põhialused

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

  • Kõrgema taseme protokolli kutse. Kui saatmisfunktsiooni kutsutakse ülaltpoolt, kontrollib saatja kõigepealt, kas aken on täis (st kas on N saadetud sõnumit, mis ootavad kinnitamist). Kui aken pole täis, moodustatakse ja edastatakse uus pakett ning muutujate väärtusi uuendatakse. Vastasel juhul tagastab saatja andmed ülemisele kihile, mis on kaudne märk sellest, et aken on täis. Tavaliselt proovib ülemine kiht andmeid mõne aja pärast uuesti edastada. Reaalses rakenduses saatja tõenäoliselt kas puhverdab andmeid (selle asemel, et neid kohe saata) või kasutab sünkroniseerimismehhanismi (nt semafor või lipp), mis võimaldaks ülemisel kihil saatmisfunktsiooni kutsuda ainult siis, kui aken pole täis.
  • Kviitungi vastuvõtmine. Protokollis väljastatakse järjekorranumbriga N paketi kohta üldine kviitung, mis näitab, et kõik N-ile eelneva järjekorranumbriga paketid on edukalt vastu võetud.
  • Aja möödumine. Protokoll kasutab taimerit pakettide ja kinnituste kadumise ning viivituste tuvastamiseks. Kui ajalõpp möödub, saadab saatja kõik kinnitamata paketid uuesti.

Valikuline kordamine

Kui akna suurus ja läbilaskevõime-viivituse korrutis on suured, võib torujuhtmes olla suur hulk pakette. Sellisel juhul võib ühe paketi viga põhjustada suure hulga pakettide uuesti saatmise, millest enamikku polnud vaja.

Näide

Top teoreetiline praktikas kogutakse praktikas rakendamise tavasid TCPJa kui keegi teab paremat viisi - 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 -kasutuse

Mehhanism
Rakendus, kommentaar

Kontrolli summa
Kasutatakse edastatud paketis olevate bitivigade tuvastamiseks.

taimer
Ajalõpuintervalli loendur ja selle aegumise näit. Viimane näitab suure tõenäosusega, et pakett või selle kinnitus läks edastamise ajal kaduma. Kui pakett toimetatakse kohale hilja, kuid ei kao (ajalõpuintervalli enneaegne aegumine) või kui kinnitus läheb kaduma, põhjustab uuesti saatmine vastuvõtja poolel duplikaatpaketi.

Seerianumber
Kasutatakse saatjalt vastuvõtjale edastatavate andmepakettide järjekorranumbrite määramiseks. Vastuvõetud pakettide järjekorranumbrite lüngad võimaldavad vastuvõtjal tuvastada pakettide kadu. Identsed pakettide järjekorranumbrid näitavad duplikaatpakette.

Kinnitus
Vastuvõtva poole poolt genereeritud ja edastavale poolele näidates, et vastav pakett või pakettide rühm on edukalt vastu võetud. Kinnitused sisaldavad tavaliselt edukalt vastuvõetud pakettide järjekorranumbreid. Sõltuvalt protokollist eristatakse individuaalseid ja grupikinnitusi.

Negatiivne kinnitus
Saaja kasutab seda saatja teavitamiseks, et paketti ei saadud õigesti vastu. Negatiivne kinnitus sisaldab tavaliselt valesti vastu võetud paketi järjekorranumbrit.

Aken, torujuhe
Need piiravad pakettide edastamiseks kasutatavate järjenumbrite vahemikku. Multisaadete edastamine ja käepigistus suurendavad protokolli läbilaskevõimet märkimisväärselt võrreldes kinnituste ootamisega. Nagu näeme, saab akna suurust arvutada vastuvõtva poole vastuvõtu- ja puhverdusvõimaluste ning võrgukoormuse põhjal.

Muud näited Go kasutamisest võrgustamiseks

В hoidlad.

Allikas: www.habr.com

Lisa kommentaar