Fundamenti di trasferimentu di dati affidabile

Fundamenti di trasferimentu di dati affidabile

À quelli chì cerca Dedicatu à capiscenu e rete è i protokolli.

Brevemente

L'articulu discute i principii di a trasmissione di dati affidabile, implementa esempii Go, cumpresi UDP è TCP. Bastu nantu à i tempi, два, trè è i libri "Computer Networks. Top-Down Approach", altrimente tutti discutanu solu Tannenbaum è Oliferov.

Protocolu di a strata di trasportu

Fornisce una cunnessione logica trà i prucessi di l'applicazione in esecuzione in diversi host. Da una perspettiva di l'applicazione, una cunnessione logica s'assumiglia à un canale chì cunnetta direttamente i prucessi.

Fundamenti di trasferimentu di dati affidabile

Protocolli di strata di trasportu sò supportati da i sistemi finali, ma micca da i router di rete (eccettu - DPI). Da u latu di u mittente, a strata di trasportu cunverte i dati di a strata di l'applicazione chì riceve da u prucessu di l'applicazione di l'invio in pacchetti di strati di trasportu chjamati segmenti.

Fundamenti di trasferimentu di dati affidabile

Questu hè fattu splitting (se necessariu) i missaghji di a capa di l'applicazione in frammenti è aghjunghjendu un capu di capa di trasportu à ognunu di elli.

Fundamenti di trasferimentu di dati affidabile

A strata di trasportu poi passa u segmentu à a capa di rete di u mittente, induve u segmentu hè incapsulatu in un pacchettu di strata di rete (datagramma) è mandatu. À a fine di riceve, a strata di a rete estrae u segmentu di a capa di trasportu da u datagramma è u passa à a capa di trasportu. In seguitu, a capa di trasportu processa u segmentu ricivutu in modu chì e so dati diventanu dispunibuli per l'applicazione chì riceve.

Fundamenti di trasferimentu di dati affidabile

Principii di trasmissione di dati affidabile

Trasmissione di dati affidabile nantu à un canale cumpletamente sicuru

U casu più simplice. U latu di l'inviu riceve simpricimenti i dati da a capa superiore, crea un pacchettu chì cuntene, è u manda à u canali.

Servidor

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

Cliente

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

Trasmissione di dati affidabile nantu à un canale cù pussibuli errori

U prossimu passu hè di assume chì tutti i pacchetti trasmessi sò ricivuti in l'ordine in quale sò stati mandati, ma i bits in elli ponu esse currutti per u fattu chì u canali trasmette qualchì volta dati cù distorsioni.

Fundamenti di trasferimentu di dati affidabile

In stu casu, i seguenti miccanismi sò usati:

  • rilevazione di errore;
  • feedback;
  • ritrasmissione.

I protokolli di trasferimentu di dati affidabili chì anu meccanismi simili per a ripetizione di a trasmissione parechje volte sò chjamati protokolli Automatic Repeat reQuest (ARQ).
Inoltre, vale a pena cunsiderà a pussibilità di l'errore in i ricivuti, quandu u partitu chì riceve ùn riceve micca infurmazione nantu à i risultati di u trasferimentu di l'ultimu pacchettu.
A suluzione à stu prublema, utilizata ancu in TCP, hè di aghjunghje un novu campu à u pacchettu di dati chì cuntene u numeru di sequenza di u pacchettu.

Fundamenti di trasferimentu di dati affidabile

Trasmissione di dati affidabile nantu à un canale inaffidabile sottumessu à distorsioni è pèrdite di pacchetti

Inseme à a distorsione, sfurtunatamenti, ci hè una perdita di pacchetti in a reta.
È per risolve stu prublema, i miccanismi sò necessarii:

  • determinà u fattu di perdita di pacchetti;
  • ri-consegna di pacchetti persi à a parte ricevente.

Inoltre, in più di a perdita di u pacchettu, hè necessariu di furnisce a pussibilità di perdita di u ricivutu o, se nunda hè persu, a so consegna cun un ritardu significativu. In tutti i casi, a listessa cosa hè fatta: u pacchettu hè ritrasmesso. Per cuntrullà u tempu, stu mecanismu usa un cronometru di countdown, chì permette di determinà a fine di l'intervallu di attesa. Allora in u pacchettu riti TPCKeepAlive hè stabilitu à 15 seconde per difettu:

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

U latu di l'inviu hà bisognu di inizià un timer ogni volta chì un pacchettu hè trasmessu (sia a prima è a seconda volta), gestisce l'interruzzioni da u timer è ferma.

Dunque, avemu familiarizatu cù i cuncetti chjave di protokolli di trasferimentu di dati affidabili:

  • checksums;
  • numeri di sequenza di pacchetti;
  • timers;
  • ricevuti pusitivi è negativi.

Ma ùn hè micca tuttu !

Protokollu di trasferimentu di dati affidabile cù pipelining

In a variante chì avemu digià cunsideratu, u protocolu di consegna affidabile hè assai inefficiente. Accumincia à "rallentà" a trasmissione furnita da u canali di cumunicazione cum'è u RTT aumenta. Per aumentà a so efficienza è aduprà megliu a capacità di u canali di cumunicazione, u pipelining hè utilizatu.

Fundamenti di trasferimentu di dati affidabile

L'usu di pipeline porta à:

  • aumentà a gamma di numeri di sequenza, postu chì tutti i pacchetti mandati (eccettu per i ritrasmissioni) deve esse identificatu unicu;
  • a necessità di aumentà i buffers nantu à i lati di trasmissione è di ricezione.

A gamma di numeri di sequenza è i requisiti di dimensione di u buffer dipendenu da l'azzioni chì u protocolu piglia in risposta à a corruzzione di pacchetti, a perdita è u ritardu. In u casu di pipelining, ci sò dui metudi per correggere l'errore:

  • riturnà N pacchetti;
  • ripetizione selettiva.

Riturnà N pacchetti - protocolu di finestra scorrevule

Fundamenti di trasferimentu di dati affidabile

U mittente deve sustene trè tippi di avvenimenti:

  • chjamate da un protocolu di livellu più altu. Quandu a funzione di mandatu di dati hè chjamata "da sopra", u latu di l'inviu verifica prima u gradu di riempimentu di a finestra (vale à dì, a prisenza di N mandati missaghji in attesa di ricivutu di ricevute). Se a finestra hè viota, un novu pacchettu hè generatu è trasmessu, è i valori variabili sò aghjurnati. Altrimenti, u latu di l'inviu torna dati à a capa superiore, è questu hè un indicazione implicita chì a finestra hè piena. Di genere, a capa superiore pruverà à trasmette i dati di novu dopu qualchì tempu. In una vera applicazione, u mittente prubabilmente o buffer i dati (invece di mandà immediatamente) o avè un mecanismu di sincronizazione (cum'è un semaforu o bandiera) chì permettenu à a capa superiore di chjamà a funzione di mandà solu quandu a finestra hè viota. .
  • riceve cunferma. In u protocolu, per un pacchettu cù numeri di sequenza N, un ricunniscenza generale hè emessu chì indica chì tutti i pacchetti cù numeri di sequenza chì precedenu N sò stati ricevuti bè.
  • l'intervallu d'attesa hè scadutu. Per determinà i fatti di pèrdite è ritardi di pacchetti è ricevuti, u protocolu usa un cronometru. Se l'intervallu di timeout scade, u latu di l'inviu rinvia tutti i pacchetti mandati micca ricunnisciuti.

Ripetizione selettiva

Quandu a dimensione di a finestra è u produttu di ritardu di propagazione di u throughput sò grande, un gran numaru di pacchetti pò esse in u pipeline. In un tali casu, un unicu errore di pacchettu pò causà un gran numaru di pacchetti per esse ritrasmessi, a maiò parte di i quali ùn eranu micca necessariu.

Esempiu:

U megliu teorichi e pratiche sò cullate in l'implementazione pratica TCP. È se qualchissia sà cumu megliu - Benvenuti.

Servidor

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

Cliente

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

cunchiusioni

Meccanismi per assicurà u trasferimentu di dati affidabile è l'usu

Mechanismu
Applicazione, cumentu

Verificate a somma
Adupratu per detect errori di bit in un pacchettu trasmessu

Timer
Cunta l'intervallu di timeout è indica quandu hè scadutu. L'ultime significa chì cù un altu gradu di probabilità u pacchettu o u so ricivutu hè persu durante a trasmissione. Se un pacchettu hè mandatu cù un ritardu, ma ùn hè micca persu (scadenza prematura di l'intervallu di timeout), o una ricevuta hè persa, a ritrasmissione porta à un pacchettu duplicatu da u latu di riceve.

Numeru d'ordine
Adupratu per a numerazione sequenziale di pacchetti di dati trasmessi da u mittente à u destinatariu. Lacune in i numeri di sequenza di pacchetti ricevuti permettenu à u receptore di detectà a perdita di pacchetti. I stessi numeri di sequenza di pacchetti significanu chì i pacchetti sò duplicati l'una di l'altru

Cunfirmazione
Generatu da l'estremità ricevente è indicà à l'estremità di l'inviu chì u pacchettu currispundente o gruppu di pacchetti hè statu ricevutu bè. Di genere, a ricunniscenza cuntene i numeri di sequenza di pacchetti ricevuti successu. Sicondu u protocolu, cunfirmazioni individuali è di gruppu sò distinti

Cunfirmazione negativa
Adupratu da u destinatariu per informà u mittente chì u pacchettu hè statu ricevutu incorrectamente. Un ricunniscenza negativu generalmente include u numeru di sequenza di u pacchettu chì ùn hè micca ricevutu currettamente

Finestra, trasportu
Limite a gamma di numeri di sequenza chì ponu esse utilizati per trasmette pacchetti. Multicast è handshake ponu aumentà significativamente u throughput di u protocolu cumparatu cù l'aspittà di ricunniscenza. Comu avemu vistu, a dimensione di a finestra pò esse calculata in basa di e capacità di ricezione è di buffering di u destinatariu, è ancu di u livellu di carica di a rete.

Più esempi di usu Go per networking

В repository.

Source: www.habr.com

Add a comment