Мәліметтерді сенімді тасымалдау негіздері

Мәліметтерді сенімді тасымалдау негіздері

Кімдерге іздейді Желілер мен хаттамаларды түсінуге арналған.

Қысқаша

Мақалада сенімді деректерді беру негіздері қарастырылады, мысалдар орындалады Go, соның ішінде UDP және TCP. Негізделген рет, два, үш және «Компьютерлік желілер. Жоғарыдан төмен көзқарас» кітаптары, әйтпесе барлығы Танненбаум мен Олиферовты ғана талқылайды.

Тасымалдау деңгейінің протоколы

Әртүрлі хосттарда орындалатын қолданбалы процестер арасындағы логикалық байланысты қамтамасыз етеді. Қолданба тұрғысынан логикалық байланыс процестерді тікелей байланыстыратын арнаға ұқсайды.

Мәліметтерді сенімді тасымалдау негіздері

Тасымалдау деңгейінің протоколдары соңғы жүйелерде қолдау көрсетіледі, бірақ желілік маршрутизаторлар қолдамайды (қоспағанда - DPI). Жіберуші жағында транспорттық деңгей жіберуші қолданба процесінен алатын қолданбалы деңгей деректерін сегменттер деп аталатын транспорттық деңгей пакеттеріне түрлендіреді.

Мәліметтерді сенімді тасымалдау негіздері

Бұл қолданбалы деңгей хабарламаларын фрагменттерге бөлу (қажет болса) және олардың әрқайсысына тасымалдау қабатының тақырыбын қосу арқылы орындалады.

Мәліметтерді сенімді тасымалдау негіздері

Содан кейін тасымалдау деңгейі сегментті жіберушінің желілік деңгейіне береді, онда сегмент желілік деңгей пакетіне (деректерге) инкапсуляцияланады және жіберіледі. Қабылдау соңында желілік деңгей датаграммадан транспорттық деңгей сегментін шығарып алып, оны тасымалдау деңгейіне береді. Әрі қарай, тасымалдау деңгейі алынған сегментті оның деректері қабылдаушы қолданбаға қолжетімді болатындай өңдейді.

Мәліметтерді сенімді тасымалдау негіздері

Мәліметтерді сенімді тасымалдау принциптері

Толығымен қауіпсіз арна арқылы сенімді деректерді беру

Ең қарапайым жағдай. Жіберуші тарап жай ғана жоғарғы қабаттан деректерді алады, оны қамтитын пакетті жасайды және оны арнаға жібереді.

Сервер

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

Клиент

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

Мүмкін қателері бар арна бойынша сенімді деректерді беру

Келесі қадам барлық жіберілген пакеттер жіберілген ретпен қабылданады деп болжауға болады, бірақ олардағы биттер арна кейде деректерді бұрмалаумен жіберетіндіктен бүлінуі мүмкін.

Мәліметтерді сенімді тасымалдау негіздері

Бұл жағдайда келесі механизмдер қолданылады:

  • қатені анықтау;
  • кері байланыс;
  • қайта жіберу.

Бірнеше рет қайталанатын тасымалдаудың ұқсас механизмдері бар сенімді деректерді тасымалдау протоколдары Automatic Repeat ReQuest (ARQ) протоколдары деп аталады.
Сонымен қатар, қабылдаушы тарап соңғы пакетті беру нәтижелері туралы ешқандай ақпаратты алмаған кезде, түбіртектерде қателер болу мүмкіндігін қарастырған жөн.
Бұл мәселені шешу TCP-де де қолданылады, пакеттің реттік нөмірін қамтитын деректер пакетіне жаңа өрісті қосу.

Мәліметтерді сенімді тасымалдау негіздері

Пакеттердің бұрмалануы мен жоғалуына байланысты сенімсіз арна арқылы сенімді деректерді беру

Бұрмалаумен қатар, өкінішке орай, желіде пакеттердің жоғалуы бар.
Және бұл мәселені шешу үшін механизмдер қажет:

  • пакеттердің жоғалу фактісін анықтау;
  • жоғалған пакеттерді қабылдаушы тарапқа қайта жеткізу.

Сонымен қатар, пакеттің жоғалуынан басқа, түбіртектің жоғалу мүмкіндігін немесе ештеңе жоғалмаған жағдайда оны айтарлықтай кешіктірумен жеткізуді қамтамасыз ету қажет. Барлық жағдайларда бірдей нәрсе жасалады: пакет қайта жіберіледі. Уақытты бақылау үшін бұл механизм күту аралығының соңын анықтауға мүмкіндік беретін кері санақ таймерін пайдаланады. Сонымен пакетте тор TCPKeepAlive әдепкі бойынша 15 секундқа орнатылған:

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

Жіберуші тарап пакет жіберілген сайын (бірінші де, екінші рет те) таймерді іске қосуы керек, таймерден үзілістерді өңдеуі және оны тоқтатуы керек.

Осылайша, біз сенімді деректерді беру хаттамаларының негізгі тұжырымдамаларымен таныстық:

  • бақылау сомасы;
  • пакеттердің реттік нөмірлері;
  • таймерлер;
  • оң және теріс түсімдер.

Бірақ бұл бәрі емес!

Құбыр желісімен сенімді деректерді беру протоколы

Біз қарастырған нұсқада сенімді жеткізу хаттамасы өте тиімсіз. Ол RTT жоғарылаған сайын байланыс арнасы қамтамасыз ететін беруді «баяулата» бастайды. Оның тиімділігін арттыру және байланыс арнасының өткізу қабілетін жақсырақ пайдалану үшін құбыр желісі қолданылады.

Мәліметтерді сенімді тасымалдау негіздері

Құбырды пайдалану мыналарға әкеледі:

  • реттік нөмірлердің ауқымын ұлғайту, өйткені барлық жіберілген пакеттер (қайта жіберулерден басқа) бірегей сәйкестендірілуі керек;
  • жіберуші және қабылдаушы жақтағы буферлерді ұлғайту қажеттілігі.

Реттік нөмір ауқымы мен буфер өлшеміне қойылатын талаптар пакеттің бүлінуіне, жоғалуына және кешігуіне жауап ретінде хаттама жасайтын әрекеттерге байланысты. Құбырды төсеу жағдайында қателерді түзетудің екі әдісі бар:

  • N пакеттерді қайтару;
  • таңдамалы қайталау.

N пакеттерге оралу – жылжымалы терезе протоколы

Мәліметтерді сенімді тасымалдау негіздері

Жіберуші оқиғаның үш түрін қолдауы керек:

  • жоғары деңгейлі хаттамамен қоңырау шалыңыз. Мәліметтерді жіберу функциясы «жоғарыдан» шақырылғанда, жіберуші тарап алдымен терезенің толтырылу дәрежесін тексереді (яғни түбіртектерді алуды күтіп тұрған N жіберілген хабарламаның болуы). Терезе бос болса, жаңа пакет жасалады және жіберіледі, ал айнымалы мәндер жаңартылады. Әйтпесе, жіберуші тарап деректерді жоғарғы қабатқа қайтарады және бұл терезенің толғанының жасырын көрсеткіші. Әдетте жоғарғы қабат біраз уақыттан кейін деректерді қайта жіберуге тырысады. Нақты қолданбада жіберуші деректерді буферлеуі мүмкін (оны дереу жіберудің орнына) немесе жоғарғы қабатқа терезе бос кезде ғана жіберу функциясын шақыруға мүмкіндік беретін синхрондау механизмі (семафор немесе жалауша) болуы мүмкін. .
  • растауды алу. Хаттамада реттік нөмірі N бар пакет үшін N алдында реттік нөмірлері бар барлық пакеттердің сәтті қабылданғанын көрсететін жалпы растау беріледі.
  • күту аралығы аяқталды. Пакеттер мен түбіртектердің жоғалуы мен кешігуі фактілерін анықтау үшін хаттама таймерді пайдаланады. Егер күту аралығы бітсе, жіберуші тарап барлық жіберілген расталмаған пакеттерді қайта жібереді.

Таңдамалы қайталау

Терезе өлшемі және өткізу қабілетінің таралу кідіріс өнімі үлкен болғанда, пакеттердің үлкен саны құбырда болуы мүмкін. Мұндай жағдайда бір пакеттік қате көптеген пакеттерді қайта жіберуге әкелуі мүмкін, олардың көпшілігі қажет емес.

Мысал:

Үздік теориялық практикалық іске асыруда тәжірибе жинақталады TCP. Егер біреу мұны жақсы білсе - Қош келдіңіздер.

Сервер

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

Клиент

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

қорытынды

Деректерді сенімді тасымалдау және пайдалануды қамтамасыз ететін механизмдер

Тетік
Өтініш, түсініктеме

Тексеру сомасы
Берілген пакеттегі бит қателерін анықтау үшін қолданылады

Таймер
Күту уақыты аралығын санайды және оның қашан біткенін көрсетеді. Соңғысы жіберу кезінде пакеттің немесе оның түбіртегінің жоғары ықтималдық дәрежесімен жоғалатынын білдіреді. Егер пакет кідіріспен жеткізілсе, бірақ жоғалмаса (тайм-аут аралығының мерзімінен бұрын аяқталуы) немесе түбіртек жоғалса, қайта жіберу қабылдаушы жағында қайталанатын пакетке әкеледі.

Реттік нөмір
Жіберушіден алушыға берілетін деректер пакеттерін ретті нөмірлеу үшін қолданылады. Қабылданған пакеттердің реттік нөмірлеріндегі бос орындар қабылдағышқа пакеттердің жоғалуын анықтауға мүмкіндік береді. Бірдей пакеттердің реттік нөмірлері пакеттердің бір-бірінің көшірмелері екенін білдіреді

Растау
Қабылдаушы жақтан жасалады және жіберуші жаққа сәйкес пакет немесе пакеттер тобы сәтті қабылданғанын көрсетеді. Әдетте растауда сәтті қабылданған пакеттердің реттік нөмірлері болады. Хаттамаға байланысты жеке және топтық растаулар ажыратылады

Теріс растау
Алушы жіберушіге пакеттің қате қабылданғаны туралы хабарлау үшін пайдаланылады. Теріс растау әдетте дұрыс қабылданбаған пакеттің реттік нөмірін қамтиды

Терезе, конвейерлеу
Пакеттерді жіберу үшін пайдалануға болатын реттік нөмірлер ауқымын шектеңіз. Көп тарату және қол алысу растауды күтумен салыстырғанда протокол өткізу қабілетін айтарлықтай арттырады. Көріп отырғанымыздай, терезе өлшемін қабылдаушы жақтың қабылдау және буферлеу мүмкіндіктеріне, сондай-ақ желінің жүктеме деңгейіне қарай есептеуге болады.

Желі үшін Go пайдаланудың қосымша мысалдары

В репозиторийлер.

Ақпарат көзі: www.habr.com

пікір қалдыру