A megbízható adatátvitel alapjai

A megbízható adatátvitel alapjai

Azoknak, akik keresi Elkötelezett a hálózatok és protokollok megértése.

tömören

A cikk a megbízható adatátvitel alapjait tárgyalja, példákat mutat be Go, beleértve az UDP-t és a TCP-t. Alapján idő, два, három és a "Számítógépes hálózatok. Felülről lefelé irányuló megközelítés" című könyveket, különben mindenki csak Tannenbaumról és Oliferovról beszél.

Szállítási réteg protokoll

Logikai kapcsolatot biztosít a különböző gazdagépeken futó alkalmazási folyamatok között. Alkalmazás szempontjából a logikai kapcsolat olyan csatornának tűnik, amely közvetlenül összeköti a folyamatokat.

A megbízható adatátvitel alapjai

Szállítási réteg protokollok végrendszerek támogatják, de a hálózati útválasztók nem (kivéve - DPI). A küldő oldalon a szállítási réteg a küldő alkalmazási folyamattól kapott alkalmazási rétegadatokat szállítási rétegbeli csomagokká, úgynevezett szegmensekké alakítja át.

A megbízható adatátvitel alapjai

Ez úgy történik, hogy (ha szükséges) az alkalmazási réteg üzeneteit töredékekre bontja, és mindegyikhez hozzáad egy szállítási réteg fejlécet.

A megbízható adatátvitel alapjai

A szállítási réteg ezután átadja a szegmenst a küldő hálózati rétegének, ahol a szegmenst egy hálózati réteg csomagba (datagramba) zárják és elküldik. A fogadó oldalon a hálózati réteg kivonja a szállítási réteg szegmenst a datagramból, és továbbítja a szállítási rétegnek. Ezután a szállítási réteg feldolgozza a fogadott szegmenst, hogy az adatai elérhetővé váljanak a fogadó alkalmazás számára.

A megbízható adatátvitel alapjai

A megbízható adatátvitel elvei

Megbízható adatátvitel teljesen biztonságos csatornán

A legegyszerűbb eset. A küldő oldal egyszerűen fogadja az adatokat a felső rétegről, létrehoz egy csomagot, amely tartalmazza azokat, és elküldi a csatornának.

Сервер

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

vásárló

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

Megbízható adatátvitel csatornán keresztül lehetséges hibákkal

Következő lépésként feltételezzük, hogy az összes továbbított csomag vétele a küldés sorrendjében történik, de a bennük lévő bitek megsérülhetnek amiatt, hogy a csatorna időnként torzulva továbbít adatokat.

A megbízható adatátvitel alapjai

Ebben az esetben a következő mechanizmusokat használják:

  • hibafelismerés;
  • Visszacsatolás;
  • újraközvetítés.

Azokat a megbízható adatátviteli protokollokat, amelyek hasonló mechanizmussal rendelkeznek az átvitel többszöri megismétlésére, automatikus ismétlési kérés (ARQ) protokolloknak nevezik.
Emellett érdemes figyelembe venni a vételi hibák lehetőségét, amikor a fogadó fél nem kap információt az utolsó csomag átvitelének eredményéről.
A TCP-ben is használt probléma megoldása az, hogy az adatcsomaghoz egy új mezőt adunk, amely tartalmazza a csomag sorszámát.

A megbízható adatátvitel alapjai

Megbízható adatátvitel megbízhatatlan csatornán, amely csomagtorzulásnak és -veszteségnek van kitéve

A torzítással együtt sajnos csomagvesztés is előfordul a hálózatban.
És a probléma megoldásához mechanizmusokra van szükség:

  • a csomagvesztés tényének meghatározása;
  • az elveszett csomagok újbóli kézbesítése a fogadó félnek.

Ezen túlmenően a csomag elvesztése mellett gondoskodni kell az átvételi elismervény elvesztésének lehetőségéről, vagy ha nem vész el, akkor jelentős késéssel történő kézbesítéséről. Minden esetben ugyanaz történik: a csomag újraküldésre kerül. Az idő szabályozására ez a mechanizmus egy visszaszámlálót használ, amely lehetővé teszi a várakozási intervallum végének meghatározását. Tehát a csomagban háló A TCPKeepAlive alapértelmezés szerint 15 másodpercre van állítva:

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

A küldő oldalnak minden egyes csomagküldéskor indítania kell egy időzítőt (mind az első, mind a második alkalommal), kezelnie kell az időzítő megszakításait és le kell állítania.

Így megismerkedtünk a megbízható adatátviteli protokollok kulcsfogalmaival:

  • ellenőrző összegek;
  • a csomagok sorszáma;
  • időzítők;
  • pozitív és negatív bevételek.

De ez még nem minden!

Megbízható adatátviteli protokoll csővezetékekkel

Az általunk már megvizsgált változatban a megbízható szállítási protokoll nagyon nem hatékony. Az RTT növekedésével elkezdi „lassítani” a kommunikációs csatorna által biztosított átvitelt. Hatékonyságának növelése és a kommunikációs csatorna kapacitásának jobb kihasználása érdekében csővezetéket alkalmaznak.

A megbízható adatátvitel alapjai

A csővezeték használata a következőkhöz vezet:

  • a sorszámok tartományának növelése, mivel minden elküldött csomagot (kivéve az újraküldést) egyedileg azonosítani kell;
  • a pufferek növelésének szükségessége az adó és a vevő oldalon.

A sorozatszám-tartomány és a pufferméret követelményei a protokoll által a csomagok sérülésére, elvesztésére és késleltetésére válaszul végrehajtott műveletektől függenek. Csővezetékezés esetén két módszer létezik a hibák kijavítására:

  • N csomag visszaküldése;
  • szelektív ismétlés.

Visszatérve N csomag – csúszó ablak protokoll

A megbízható adatátvitel alapjai

A feladónak három eseménytípust kell támogatnia:

  • magasabb szintű protokollal hívja. Amikor az adatküldő funkciót „felülről” hívjuk, a küldő oldal először az ablak kitöltöttségét (vagyis N darab nyugtára váró üzenet meglétét) ellenőrzi. Ha az ablak üres, a rendszer új csomagot generál és továbbít, és frissíti a változó értékeket. Ellenkező esetben a küldő oldal visszaküldi az adatokat a felső rétegnek, és ez implicit jelzi, hogy az ablak megtelt. Általában a felső réteg egy idő után újra megpróbálja továbbítani az adatokat. Valós alkalmazásban a küldő valószínűleg vagy pufferelné az adatokat (ahelyett, hogy azonnal elküldené), vagy van egy szinkronizálási mechanizmusa (például egy szemafor vagy zászló), amely lehetővé teszi a felső réteg számára, hogy csak akkor hívja meg a küldési funkciót, ha az ablak üres. .
  • megerősítést kap. A protokollban az N sorszámú csomagra általános nyugtázást adnak ki, amely jelzi, hogy az összes N előtti sorszámú csomagot sikeresen fogadták.
  • a várakozási idő lejárt. A csomagok és bevételek elvesztésének és késésének tényeinek meghatározásához a protokoll időzítőt használ. Ha az időkorlát lejár, a küldő oldal újra elküldi az összes elküldött nyugtázatlan csomagot.

Szelektív ismétlés

Ha az ablak mérete és az átviteli sebesség-terjedés késleltetési szorzata nagy, nagyszámú csomag lehet folyamatban. Ilyen esetben egyetlen csomaghiba nagy számú csomag újraküldését okozhatja, amelyek többségére nem volt szükség.

Példa

Felső elméleti gyakorlatok összegyűjtése a gyakorlati megvalósítás során TCP. És ha valaki tudja, hogyan a legjobb... fogadtatás.

Сервер

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

vásárló

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

Teljesítmény

A megbízható adatátvitelt és -használatot biztosító mechanizmusok

Механизм
Jelentkezés, hozzászólás

Ellenőrző összeg
A továbbított csomagban lévő bithibák észlelésére szolgál

időzítő
Visszaszámolja az időtúllépési intervallumot, és jelzi, ha lejárt. Ez utóbbi azt jelenti, hogy nagy valószínűséggel a csomag vagy annak vétele elveszik az átvitel során. Ha egy csomagot késéssel kézbesítenek, de nem vesznek el (az időtúllépési idő idő előtti lejárta), vagy egy nyugta elveszik, az újraküldés a fogadó oldalon duplikált csomaghoz vezet.

Sorozatszám
A feladótól a címzettig továbbított adatcsomagok sorszámozására szolgál. A fogadott csomagok sorszámának hézagai lehetővé teszik a vevő számára a csomagvesztés észlelését. Az azonos csomagsorszámok azt jelentik, hogy a csomagok egymás másolatai

megerősítés
A fogadó vég generálja, és jelzi a küldő végnek, hogy a megfelelő csomag vagy csomagcsoport sikeresen vétele megtörtént. A nyugtázás jellemzően a sikeresen fogadott csomagok sorszámát tartalmazza. A protokolltól függően egyéni és csoportos megerősítéseket különböztetnek meg

Negatív megerősítés
A címzett arra használja, hogy tájékoztassa a feladót, hogy a csomag hibásan érkezett. A negatív nyugtázás általában a nem megfelelően fogadott csomag sorszámát tartalmazza

Ablak, szállítószalag
Korlátozza a csomagok továbbítására használható sorszámok tartományát. A csoportos küldés és a kézfogás jelentősen megnövelheti a protokoll átviteli sebességét a nyugtázásra való várakozáshoz képest. Amint látni fogjuk, az ablak mérete a fogadó oldal vételi és pufferelési képességei, valamint a hálózat terhelési szintje alapján számítható ki.

További példák a Go hálózati használatára

В adattárak.

Forrás: will.com

Hozzászólás