Uzticamas datu pārsūtīšanas pamati

Uzticamas datu pārsūtīšanas pamati

Tiem, kuri meklē Veltīts tīklu un protokolu izpratnei.

Īsumā

Rakstā apskatīti uzticamas datu pārraides pamati, ieviesti piemēri Go, tostarp UDP un TCP. Balstoties uz laiks, два, trīs un grāmatas "Datortīkli. No augšas uz leju pieeja", citādi visi apspriež tikai Tannenbaumu un Oliferovu.

Transporta slāņa protokols

Nodrošina loģisku savienojumu starp lietojumprogrammu procesiem, kas darbojas dažādos resursdatoros. No lietojumprogrammas viedokļa loģiskais savienojums izskatās kā kanāls, kas tieši savieno procesus.

Uzticamas datu pārsūtīšanas pamati

Transporta slāņa protokoli atbalsta gala sistēmas, bet ne tīkla maršrutētāji (izņemot - DPI). No sūtītāja puses transporta slānis pārvērš lietojumprogrammas slāņa datus, ko tas saņem no lietojumprogrammas nosūtīšanas procesa, transporta slāņa paketēs, ko sauc par segmentiem.

Uzticamas datu pārsūtīšanas pamati

Tas tiek darīts, sadalot (ja nepieciešams) lietojumprogrammas slāņa ziņojumus fragmentos un katram no tiem pievienojot transporta slāņa galveni.

Uzticamas datu pārsūtīšanas pamati

Pēc tam transporta slānis nodod segmentu sūtītāja tīkla slānim, kur segments tiek iekapsulēts tīkla slāņa paketē (datagrammā) un nosūtīts. Saņemšanas galā tīkla slānis no datagrammas izņem transporta slāņa segmentu un nodod to transporta slānim. Pēc tam transporta slānis apstrādā saņemto segmentu, lai tā dati kļūtu pieejami saņēmējai lietojumprogrammai.

Uzticamas datu pārsūtīšanas pamati

Uzticamas datu pārraides principi

Uzticama datu pārraide pa pilnīgi drošu kanālu

Vienkāršākais gadījums. Sūtītāja puse vienkārši saņem datus no augšējā slāņa, izveido to saturošu paketi un nosūta to kanālam.

Serveris

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

Klients

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

Uzticama datu pārraide pa kanālu ar iespējamām kļūdām

Nākamais solis ir pieņemt, ka visas pārsūtītās paketes tiek saņemtas tādā secībā, kādā tās tika nosūtītas, taču tajās esošie biti var tikt bojāti, jo kanāls dažkārt pārraida datus ar traucējumiem.

Uzticamas datu pārsūtīšanas pamati

Šajā gadījumā tiek izmantoti šādi mehānismi:

  • kļūdu noteikšana;
  • atgriezeniskā saite;
  • retranslācija.

Uzticami datu pārsūtīšanas protokoli, kuriem ir līdzīgi mehānismi pārraides atkārtošanai vairākas reizes, tiek saukti par automātiskās atkārtošanas pieprasījuma (ARQ) protokoliem.
Turklāt ir vērts apsvērt kļūdu iespējamību kvītīs, kad saņēmēja puse nesaņems nekādu informāciju par pēdējās paketes pārsūtīšanas rezultātiem.
Šīs problēmas risinājums, ko izmanto arī TCP, ir datu paketei pievienot jaunu lauku, kurā ir paketes kārtas numurs.

Uzticamas datu pārsūtīšanas pamati

Uzticama datu pārraide pa neuzticamu kanālu, kas pakļauta pakešu kropļojumiem un zudumiem

Diemžēl līdz ar kropļojumiem tīklā ir arī pakešu zudumi.
Un, lai atrisinātu šo problēmu, ir nepieciešami mehānismi:

  • pakešu zuduma fakta noteikšana;
  • nozaudēto pakešu atkārtota piegāde saņēmējai pusei.

Turklāt papildus pakas nozaudēšanai ir jāparedz iespēja pazaudēt čeku vai, ja nekas nav pazaudēts, tā piegāde ar ievērojamu kavēšanos. Visos gadījumos tiek darīts tas pats: pakete tiek pārsūtīta atkārtoti. Lai kontrolētu laiku, šis mehānisms izmanto atpakaļskaitīšanas taimeri, kas ļauj noteikt gaidīšanas intervāla beigas. Tātad iepakojumā neto TCPKeepAlive pēc noklusējuma ir iestatīts uz 15 sekundēm:

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

Sūtītājam ir jāieslēdz taimeris katru reizi, kad tiek pārsūtīta pakete (gan pirmo, gan otro reizi), jāapstrādā taimera radītie pārtraukumi un jāpārtrauc tas.

Tātad, mēs esam iepazinušies ar uzticamu datu pārsūtīšanas protokolu galvenajiem jēdzieniem:

  • kontrolsummas;
  • paku kārtas numuri;
  • taimeri;
  • pozitīvie un negatīvie ieņēmumi.

Bet tas vēl nav viss!

Uzticams datu pārraides protokols ar konveijeru

Mūsu jau aplūkotajā variantā uzticamais piegādes protokols ir ļoti neefektīvs. Palielinoties RTT, tas sāk “palēnināt” pārraidi, ko nodrošina sakaru kanāls. Lai palielinātu tā efektivitāti un labāk izmantotu sakaru kanāla jaudu, tiek izmantota cauruļvadu sistēma.

Uzticamas datu pārsūtīšanas pamati

Cauruļvadu izmantošana noved pie:

  • kārtas numuru diapazona palielināšana, jo visām nosūtītajām paketēm (izņemot atkārtotas pārraides) jābūt unikāli identificētām;
  • nepieciešamība palielināt buferus raidīšanas un uztveršanas pusēs.

Prasības pēc kārtas numuru diapazona un bufera lieluma ir atkarīgas no darbībām, ko protokols veic, reaģējot uz pakešu sabojāšanu, zudumu un kavēšanos. Cauruļvada gadījumā kļūdu labošanai ir divas metodes:

  • atgriezt N paketes atpakaļ;
  • selektīvs atkārtojums.

Atgriežoties N paketes - bīdāmo logu protokols

Uzticamas datu pārsūtīšanas pamati

Sūtītājam ir jāatbalsta trīs veidu pasākumi:

  • zvanu, izmantojot augstāka līmeņa protokolu. Kad datu nosūtīšanas funkcija tiek izsaukta “no augšas”, sūtītāja puse vispirms pārbauda loga aizpildījuma pakāpi (tas ir, vai N nosūtītu ziņojumu, kas gaida kvīšu saņemšanu). Ja logs ir tukšs, tiek ģenerēta un pārsūtīta jauna pakete, kā arī tiek atjauninātas mainīgās vērtības. Pretējā gadījumā sūtītāja puse atgriež datus augšējam slānim, un tā ir netieša norāde, ka logs ir pilns. Parasti augšējais slānis pēc kāda laika mēģinās vēlreiz pārsūtīt datus. Reālā lietojumprogrammā sūtītājs, visticamāk, vai nu buferētu datus (nevis tos nekavējoties nosūtītu), vai arī izmantotu sinhronizācijas mehānismu (piemēram, semaforu vai karogu), kas ļautu augšējam slānim izsaukt sūtīšanas funkciju tikai tad, kad logs ir tukšs. .
  • saņemot apstiprinājumu. Protokolā paketei ar kārtas numuru N tiek izsniegts vispārējs apstiprinājums, kas norāda, ka visas paketes ar kārtas numuriem pirms N ir veiksmīgi saņemtas.
  • gaidīšanas intervāls ir beidzies. Lai noteiktu pakešu un kvīšu zudumu un kavējumu faktus, protokolā tiek izmantots taimeris. Ja taimauta intervāls beidzas, sūtītāja puse atkārtoti nosūta visas nosūtītās neapstiprinātās paketes.

Selektīvs atkārtojums

Ja loga izmērs un caurlaidspējas izplatīšanās aizkaves produkts ir liels, var tikt sagatavots liels skaits pakešu. Šādā gadījumā vienas paketes kļūdas dēļ var atkārtoti nosūtīt lielu skaitu pakešu, no kurām lielākā daļa nebija nepieciešamas.

Piemērs

Tops teorētiski prakse tiek apkopota praktiskajā īstenošanā TCP. Un, ja kāds zina, kā vislabāk - gaidīts.

Serveris

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

Klients

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

secinājums

Mehānismi uzticamas datu pārraides un lietošanas nodrošināšanai

mehānisms
Pieteikums, komentārs

Pārbaudes summa
Izmanto, lai atklātu bitu kļūdas pārsūtītajā paketē

Taimeris
Atskaita taimauta intervālu un norāda, kad tas ir beidzies. Pēdējais nozīmē, ka ar lielu varbūtības pakāpi pārraides laikā tiek zaudēta pakete vai tās saņemšana. Ja pakete tiek piegādāta ar kavēšanos, bet netiek pazaudēta (priekšlaicīga taimauta intervāla beigas) vai kvīts tiek pazaudēta, atkārtota pārsūtīšana noved pie paketes dublikāta saņēmēja pusē.

Sērijas numurs
Izmanto datu pakešu secīgai numerācijai, kas tiek pārsūtītas no sūtītāja uz saņēmēju. Saņemto pakešu kārtas numuru nepilnības ļauj uztvērējam noteikt pakešu zudumu. Tie paši pakešu kārtas numuri nozīmē, ka paketes ir viena otras dublikāti

Apstiprinājums
Ģenerē saņēmējs un norāda sūtīšanas beigām, ka atbilstošā pakete vai pakešu grupa ir veiksmīgi saņemta. Parasti apstiprinājumā ir ietverti veiksmīgi saņemto pakešu kārtas numuri. Atkarībā no protokola izšķir individuālus un grupu apstiprinājumus

Negatīvs apstiprinājums
To izmanto saņēmējs, lai informētu sūtītāju, ka pakete ir saņemta nepareizi. Negatīvā apstiprinājumā parasti ir iekļauts nepareizi saņemtās paketes kārtas numurs

Logs, konveijers
Ierobežojiet kārtas numuru diapazonu, ko var izmantot pakešu pārsūtīšanai. Multiraide un rokasspiediens var ievērojami palielināt protokola caurlaidspēju, salīdzinot ar apstiprinājumu gaidīšanu. Kā redzēsim, loga izmēru var aprēķināt, pamatojoties uz uztveršanas gala un buferizācijas iespējām, kā arī tīkla slodzes līmeni

Vairāk piemēru Go izmantošanai tīklošanai

В krātuves.

Avots: www.habr.com

Pievieno komentāru