Fundamentoj de Fidinda Transdono de Datumoj

Fundamentoj de Fidinda Transdono de Datumoj

Al tiuj, kiuj serĉas Dediĉita al kompreno de retoj kaj protokoloj.

Mallonge

La artikolo diskutas la bazojn de fidinda datumtranssendo, efektivigas ekzemplojn pri Go, inkluzive de UDP kaj TCP. Bazita sur fojoj, два, tri kaj la libroj "Komputilaj Retoj. Desupra Aliro", alie ĉiuj diskutas nur Tannenbaum kaj Oliferov.

Protokolo pri transporta tavolo

Provizas logikan ligon inter aplikaĵprocezoj kurantaj sur malsamaj gastigantoj. De aplika perspektivo, logika konekto aspektas kiel kanalo, kiu rekte ligas procezojn.

Fundamentoj de Fidinda Transdono de Datumoj

Protokoloj pri transporta tavolo estas subtenataj de finsistemoj, sed ne de retaj enkursigiloj (krom - DPI). Sur la sendintoflanko, la transporttavolo konvertas la aplikaĵtavoldatenojn kiujn ĝi ricevas de la senda aplikaĵprocezo en transporttavolpakaĵojn nomitajn segmentoj.

Fundamentoj de Fidinda Transdono de Datumoj

Ĉi tio estas farita disigante (se necese) la aplikaĵtavolmesaĝojn en fragmentojn kaj aldonante transporttavolan kaplinion al ĉiu el ili.

Fundamentoj de Fidinda Transdono de Datumoj

La transporttavolo tiam pasas la segmenton al la rettavolo de la sendinto, kie la segmento estas enkapsuligita en rettavolpakaĵeto (datagramo) kaj sendita. Ĉe la riceva fino, la rettavolo ĉerpas la transporttavolsegmenton de la datagramo kaj pasas ĝin supren al la transporttavolo. Poste, la transporttavolo prilaboras la ricevitan segmenton tiel ke ĝiaj datenoj iĝas haveblaj al la ricevanta aplikaĵo.

Fundamentoj de Fidinda Transdono de Datumoj

Principoj de fidinda transdono de datumoj

Fidinda transdono de datumoj per tute sekura kanalo

La plej simpla kazo. La senda flanko simple ricevas la datumojn de la supra tavolo, kreas pakaĵeton enhavantan ĝin, kaj sendas ĝin al la kanalo.

Servilo

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

Kliento

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

Fidinda transdono de datumoj tra kanalo kun eblaj eraroj

La sekva paŝo estas supozi, ke ĉiuj elsenditaj pakoj estas ricevitaj en la ordo en kiu ili estis senditaj, sed la bitoj en ili povas esti koruptitaj pro la fakto, ke la kanalo foje transdonas datumojn kun misprezentoj.

Fundamentoj de Fidinda Transdono de Datumoj

En ĉi tiu kazo, la sekvaj mekanismoj estas uzataj:

  • erardetekto;
  • retrosciigo;
  • retranssendo.

Fidindaj datumtransigo-protokoloj kiuj havas similajn mekanismojn por ripetado de dissendo plurfoje estas nomitaj Automatic Repeat reQuest (ARQ) protokoloj.
Aldone, indas konsideri la eblecon de eraroj en kvitancoj, kiam la ricevanto ne ricevos informojn pri la rezultoj de la translokigo de la lasta pako.
La solvo al ĉi tiu problemo, ankaŭ uzata en TCP, estas aldoni novan kampon al la datumpakaĵo enhavanta la sinsekvon de la pako.

Fundamentoj de Fidinda Transdono de Datumoj

Fidinda datumtranssendo tra nefidinda kanalo kondiĉigita de pakaĵeto misprezento kaj perdo

Kune kun distordo, bedaŭrinde, estas paka perdo en la reto.
Kaj por solvi ĉi tiun problemon, necesas mekanismoj:

  • determini la fakton de paka perdo;
  • retransdono de perditaj pakaĵoj al la ricevanto.

Aldone, krom la perdo de la pako, necesas antaŭvidi la eblecon de perdo de la kvitanco aŭ, se nenio estas perdita, ĝian liveron kun grava prokrasto. En ĉiuj kazoj oni faras la samon: la pako estas retransdonata. Por kontroli tempon, ĉi tiu mekanismo uzas retronombradon, kiu permesas vin determini la finon de la atenda intervalo. Do en la pakaĵo net TPCKeepAlive estas agordita al 15 sekundoj defaŭlte:

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

La sendanta flanko devas komenci tempigilon ĉiufoje kiam pakaĵeto estas elsendita (kaj la unua kaj la duan fojon), trakti interrompojn de la tempigilo kaj haltigi ĝin.

Do, ni konatiĝis kun la ŝlosilaj konceptoj de fidindaj datumtransigo-protokoloj:

  • ĉeksumoj;
  • sinsekvaj nombroj de pakoj;
  • temporiziloj;
  • pozitivaj kaj negativaj kvitancoj.

Sed tio ne estas ĉio!

Fidinda datumtransiga protokolo kun dukto

En la varianto, kiun ni jam konsideris, la fidinda livera protokolo estas tre malefika. Ĝi komencas "malrapidigi" la transdonon provizitan de la komunika kanalo dum la RTT pliiĝas. Por pliigi ĝian efikecon kaj pli bone utiligi la komunikadkanalan kapaciton, dukto estas uzata.

Fundamentoj de Fidinda Transdono de Datumoj

La uzo de dukto kondukas al:

  • pliigante la gamon de sekvencnombroj, ĉar ĉiuj senditaj pakaĵetoj (krom redissendoj) devas esti unike identigitaj;
  • la bezono pliigi bufrojn sur la elsendaj kaj ricevantaj flankoj.

La sekvencnumerintervalo kaj bufrograndecpostuloj dependas de la agoj kiujn la protokolo prenas en respondo al pakaĵetkorupto, perdo, kaj prokrasto. En la kazo de dukto, ekzistas du metodoj por korekti erarojn:

  • resendi N pakojn;
  • selektema ripeto.

Reiri N pakojn - glitfenestra protokolo

Fundamentoj de Fidinda Transdono de Datumoj

La sendinto devas subteni tri specojn de eventoj:

  • voki per pli alta nivela protokolo. Kiam la funkcio de sendo de datumoj nomiĝas "de supre", la senda flanko unue kontrolas la gradon de plenigo de la fenestro (tio estas, la ĉeesto de N senditaj mesaĝoj atendantaj ricevon de kvitancoj). Se la fenestro estas malplena, nova pako estas generita kaj transdonita, kaj la variaj valoroj estas ĝisdatigitaj. Alie, la senda flanko resendas datumojn al la supra tavolo, kaj ĉi tio estas implica indiko, ke la fenestro estas plena. Tipe la supra tavolo provos transdoni la datumojn denove post iom da tempo. En reala aplikiĝo, la sendinto verŝajne aŭ bufrus la datenojn (anstataŭ sendi ĝin tuj) aŭ havus sinkronigan mekanismon (kiel ekzemple semaforo aŭ flago) kiu permesus al la supra tavolo voki la sendan funkcion nur kiam la fenestro estas malplena. .
  • ricevante konfirmon. En la protokolo, por pakaĵeto kun sekvencnumero N, ĝenerala agnosko estas emisiita indikante ke ĉiuj pakaĵetoj kun sekvencnombroj antaŭantaj N estis sukcese ricevitaj.
  • la atenda intervalo eksvalidiĝis. Por determini la faktojn de perdoj kaj malfruoj de pakoj kaj kvitancoj, la protokolo uzas tempigilon. Se la tempintervalo eksvalidiĝas, la senda flanko resendas ĉiujn senditajn neagnoskitajn pakaĵetojn.

Selektema ripeto

Kiam la fenestra grandeco kaj la trai-disvastiga prokrasto-produkto estas grandaj, granda nombro da pakaĵetoj povas esti en la dukto. En tia kazo, ununura paka eraro povas kaŭzi grandan nombron da pakaĵetoj esti retranssenditaj, la plej multaj el kiuj ne estis postulataj.

Ekzemplo:

La plej bona teoria praktikoj estas kolektitaj en praktika efektivigo TCP. Kaj se iu scias kiel plej bone - bonvenon.

Servilo

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

Kliento

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

konkludo

Mekanismoj por certigi fidindan translokigon kaj uzon de datumoj

Механизм
Apliko, komento

Kontrola sumo
Uzita por detekti bitajn erarojn en elsendita pakaĵeto

Tempigilo
Nombras malsupren la paŭzintervalo kaj indikas kiam ĝi eksvalidiĝis. Ĉi-lasta signifas, ke kun alta grado de probableco la pakaĵo aŭ ĝia kvitanco perdiĝas dum transdono. Se pakaĵeto estas liverita kun prokrasto, sed ne estas perdita (malfrua eksvalidiĝo de la tempo-intervalo), aŭ kvitanco estas perdita, retranssendo kondukas al duplikata pakaĵeto ĉe la ricevanta flanko.

Seria numero
Uzite por sinsekva numerado de datumpakaĵoj elsenditaj de sendinto ĝis ricevanto. Interspacoj en la sekvencnombroj de ricevitaj pakaĵetoj permesas al la ricevilo detekti pakaĵetperdon. La samaj pakaj sekvencnombroj signifas ke la pakaĵetoj estas duplikatoj unu de la alia

Konfirmo
Generita de la ricevanta fino kaj indikanta al la sendanta fino ke la responda pakaĵeto aŭ grupo de pakoj estis sukcese ricevita. Tipe la agnosko enhavas la sekvencnombrojn de sukcese ricevitaj pakaĵetoj. Depende de la protokolo oni distingas individuajn kaj grupajn konfirmojn

Negativa konfirmo
Uzita de la ricevanto por informi la sendinton, ke la pako estis ricevita malĝuste. Negativa agnosko kutime inkluzivas la sinsekvon de la pakaĵeto kiu ne estis ĝuste ricevita

Window, conveyorization
Limigu la gamon de sinsekvaj nombroj, kiuj povas esti uzataj por transdoni pakaĵojn. Multicast kaj manpremo povas signife pliigi protokolan trairon kompare kun atendado de agnoskoj. Kiel ni vidos, la fenestra grandeco povas esti kalkulita surbaze de la ricevaj kaj bufraj kapabloj de la riceva fino, same kiel la reta ŝarĝnivelo.

Pliaj ekzemploj de uzado de Go por interkonektado

В deponejoj.

fonto: www.habr.com

Aldoni komenton