Основи на доверлив пренос на податоци

Основи на доверлив пренос на податоци

На оние кои бара Посветен на разбирање на мрежи и протоколи.

Накратко

Написот ги разгледува основите на сигурен пренос на податоци, имплементира примери на 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)
    }
}

Сигурен пренос на податоци преку канал со можни грешки

Следниот чекор е да се претпостави дека сите испратени пакети се примаат по редоследот по кој се испратени, но битовите во нив може да бидат оштетени поради фактот што каналот понекогаш пренесува податоци со изобличувања.

Основи на доверлив пренос на податоци

Во овој случај, се користат следниве механизми:

  • откривање на грешки;
  • повратни информации;
  • реемитување.

Сигурните протоколи за пренос на податоци кои имаат слични механизми за повторување на преносот повеќе пати се нарекуваат протоколи за автоматско повторување барање (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)
    }
}

Излез

Механизми за обезбедување сигурен пренос и употреба на податоци

Механизам
Апликација, коментар

Проверете ја сумата
Се користи за откривање на бит-грешки во пренесен пакет

Тајмер
Го одбројува временскиот интервал и покажува кога истекол. Последново значи дека со висок степен на веројатност пакетот или неговиот прием се губи при преносот. Ако пакетот се испорача со задоцнување, но не е изгубен (предвремено истекување на временскиот интервал) или се изгуби сметката, реемитувањето води до дупликат пакет на примачката страна

Сериски број
Се користи за секвенцијално нумерирање на пакети со податоци пренесени од испраќач до примач. Празнините во секвенциските броеви на примените пакети му овозможуваат на примачот да открие загуба на пакети. Истите броеви на низа на пакети значат дека пакетите се дупликати еден на друг

Потврда
Генерирани од страна на приемниот крај и означувајќи на крајот на испраќање дека соодветниот пакет или група пакети се успешно примени. Типично, потврдата ги содржи секвенциските броеви на успешно примените пакети. Во зависност од протоколот, се разликуваат поединечни и групни потврди

Негативна потврда
Се користи од примачот за да го информира испраќачот дека пакетот е погрешно примен. Негативната потврда обично го вклучува секвенцискиот број на пакетот што не бил правилно примен

Прозорец, транспортеризација
Ограничете го опсегот на секвентни броеви што може да се користат за пренос на пакети. Multicast и ракување може значително да го зголемат протокот на протокол во споредба со чекањето за признанија. Како што ќе видиме, големината на прозорецот може да се пресмета врз основа на можностите за прием и баферирање на приемниот крај, како и нивото на оптоварување на мрежата

Повеќе примери за користење Go за вмрежување

В складишта.

Извор: www.habr.com

Додадете коментар