Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Σε αυτούς που αναζητά Αφιερωμένο στην κατανόηση δικτύων και πρωτοκόλλων.

Εν συντομία

Το άρθρο συζητά τα βασικά της αξιόπιστης μετάδοσης δεδομένων και εφαρμόζει παραδείγματα σχετικά με Go, συμπεριλαμβανομένων των UDP και TCP. Με βάση ώρα, два, τρία και το βιβλίο "Δίκτυα Υπολογιστών. Μια Προσέγγιση από Πάνω προς τα Κάτω", κατά τα άλλα όλοι συζητούν μόνο για τους Tannenbaum και Oliferov.

Πρωτόκολλο επιπέδου μεταφοράς

Παρέχει μια λογική σύνδεση μεταξύ διεργασιών εφαρμογών που εκτελούνται σε διαφορετικούς κεντρικούς υπολογιστές. Μια λογική σύνδεση, από την οπτική γωνία μιας εφαρμογής, εμφανίζεται ως ένα κανάλι που συνδέει άμεσα τις διεργασίες.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Πρωτόκολλα επιπέδου μεταφοράς υποστηρίζεται από τα τερματικά συστήματα αλλά όχι από τους δρομολογητές δικτύου (εκτός από - DPI). Από την πλευρά του αποστολέα, το επίπεδο μεταφοράς μετατρέπει τα δεδομένα του επιπέδου εφαρμογής που λαμβάνει από τη διεργασία εφαρμογής μετάδοσης σε πακέτα επιπέδου μεταφοράς που ονομάζονται τμήματα.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Αυτό γίνεται διασπώντας (εάν είναι απαραίτητο) τα μηνύματα του επιπέδου εφαρμογής σε τμήματα και προσθέτοντας μια κεφαλίδα επιπέδου μεταφοράς σε καθένα από αυτά.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Το επίπεδο μεταφοράς στη συνέχεια μεταβιβάζει το τμήμα στο επίπεδο δικτύου του αποστολέα, όπου το τμήμα ενθυλακώνεται σε ένα πακέτο επιπέδου δικτύου (datagram) και αποστέλλεται. Στην πλευρά λήψης, το επίπεδο δικτύου εξάγει το τμήμα του επιπέδου μεταφοράς από το datagram και το μεταβιβάζει στο επίπεδο μεταφοράς. Το επίπεδο μεταφοράς επεξεργάζεται στη συνέχεια το ληφθέν τμήμα έτσι ώστε τα δεδομένα του να γίνουν διαθέσιμα στην εφαρμογή λήψης.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Αρχές ασφαλούς μετάδοσης δεδομένων

Αξιόπιστη μετάδοση δεδομένων μέσω ενός απόλυτα ασφαλούς καναλιού

Η πιο απλή περίπτωση. Η πλευρά αποστολής απλώς λαμβάνει δεδομένα από το ανώτερο επίπεδο, δημιουργεί ένα πακέτο που τα περιέχει και τα στέλνει μέσω του καναλιού.

Διακομιστή

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

Αξιόπιστη μετάδοση δεδομένων μέσω καναλιού με πιθανά σφάλματα

Το επόμενο βήμα είναι να υποθέσουμε ότι όλα τα μεταδιδόμενα πακέτα λαμβάνονται με τη σειρά που στάλθηκαν, αλλά τα bit σε αυτά ενδέχεται να είναι αλλοιωμένα λόγω του γεγονότος ότι το κανάλι μερικές φορές μεταδίδει δεδομένα με παραμορφώσεις.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Σε αυτήν την περίπτωση, εφαρμόζονται οι ακόλουθοι μηχανισμοί:

  • ανίχνευση σφαλμάτων;
  • ανατροφοδότηση;
  • αναμετάδοση.

Τα αξιόπιστα πρωτόκολλα μετάδοσης δεδομένων που διαθέτουν τέτοιους μηχανισμούς για πολλαπλή επανάληψη μετάδοσης ονομάζονται πρωτόκολλα Αυτόματης Επανάληψης Αίτησης (ARQ).
Επιπλέον, αξίζει να εξεταστεί η πιθανότητα σφαλμάτων στις αποδείξεις, όταν το μέρος που λαμβάνει το μήνυμα δεν λαμβάνει καμία πληροφορία σχετικά με τα αποτελέσματα της μεταφοράς του τελευταίου πακέτου.
Η λύση σε αυτό το πρόβλημα, που χρησιμοποιείται μεταξύ άλλων στο TCP, είναι η προσθήκη ενός νέου πεδίου στο πακέτο δεδομένων που περιέχει τον αριθμό ακολουθίας του πακέτου.

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Αξιόπιστη μετάδοση δεδομένων μέσω ενός αναξιόπιστου καναλιού που επιτρέπει παραμόρφωση και απώλεια πακέτων

Μαζί με τις παραμορφώσεις, δυστυχώς, υπάρχει και απώλεια πακέτων στο δίκτυο.
Και για να λυθεί αυτό το πρόβλημα, απαιτούνται μηχανισμοί:

  • προσδιορισμός του γεγονότος της απώλειας πακέτων·
  • επαναπαράδοση χαμένων πακέτων στον παραλήπτη.

Επιπλέον, εκτός από την απώλεια του δέματος, είναι απαραίτητο να προβλεφθεί η πιθανότητα απώλειας της απόδειξης ή, εάν δεν χαθεί τίποτα, η παράδοσή της με σημαντική καθυστέρηση. Σε όλες τις περιπτώσεις, συμβαίνει το ίδιο πράγμα: το πακέτο επαναμεταδίδεται. Για τον έλεγχο του χρόνου, αυτός ο μηχανισμός χρησιμοποιεί ένα χρονόμετρο αντίστροφης μέτρησης, το οποίο σας επιτρέπει να προσδιορίσετε το τέλος του διαστήματος αναμονής. Έτσι, στη συσκευασία καθαρά Το TCPKeepAlive έχει οριστεί στα 15 δευτερόλεπτα από προεπιλογή:

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

Η πλευρά μετάδοσης πρέπει να ξεκινά τον χρονοδιακόπτη κάθε φορά που μεταδίδεται ένα πακέτο (τόσο την πρώτη όσο και τη δεύτερη φορά), να χειρίζεται τις διακοπές από τον χρονοδιακόπτη και να το σταματά.

Έτσι, έχουμε εξοικειωθεί με τις βασικές έννοιες των αξιόπιστων πρωτοκόλλων μετάδοσης δεδομένων:

  • αθροίσματα ελέγχου;
  • σειριακούς αριθμούς δεμάτων·
  • χρονόμετρα;
  • θετικές και αρνητικές εισπράξεις.

Αλλά αυτό δεν είναι όλο!

Αξιόπιστο πρωτόκολλο μεταφοράς δεδομένων με αγωγό

Στην έκδοση που έχουμε ήδη εξετάσει, το αξιόπιστο πρωτόκολλο παράδοσης είναι πολύ αναποτελεσματικό. Αρχίζει να «επιβραδύνει» τη μετάδοση που παρέχεται από το κανάλι επικοινωνίας καθώς αυξάνεται το RTT. Για την αύξηση της αποδοτικότητάς του και την καλύτερη αξιοποίηση της χωρητικότητας του καναλιού επικοινωνίας, χρησιμοποιείται η διοχέτευση (pipelining).

Βασικές αρχές αξιόπιστης μεταφοράς δεδομένων

Η χρήση της σωλήνωσης έχει ως αποτέλεσμα:

  • αύξηση του εύρους των αριθμών ακολουθίας, καθώς όλα τα αποστέλλοντα πακέτα (εκτός από τις αναμεταδόσεις) πρέπει να είναι μοναδικά αναγνωρίσιμα·
  • η ανάγκη αύξησης των buffer στις πλευρές μετάδοσης και λήψης.

Το εύρος των αριθμών ακολουθίας και οι απαιτήσεις μεγέθους buffer εξαρτώνται από τις ενέργειες που λαμβάνει το πρωτόκολλο σε απόκριση σε περίπτωση καταστροφής, απώλειας και καθυστέρησης πακέτων. Στην περίπτωση της διοχέτευσης, υπάρχουν δύο μέθοδοι διόρθωσης σφαλμάτων:

  • επιστρέφει 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)
    }
}

Παραγωγή

Μηχανισμοί που διασφαλίζουν την αξιόπιστη μετάδοση και χρήση δεδομένων

Μηχανισμός
Εφαρμογή, σχόλιο

Άθροισμα ελέγχου
Χρησιμοποιείται για την ανίχνευση σφαλμάτων bit σε ένα μεταδιδόμενο πακέτο.

χρονόμετρο
Μετρώντας αντίστροφα το χρονικό όριο και υποδεικνύοντας τη λήξη του. Το τελευταίο σημαίνει ότι υπάρχει μεγάλη πιθανότητα το πακέτο ή η απόδειξή του να χάθηκε κατά τη μετάδοση. Εάν ένα πακέτο παραδοθεί καθυστερημένα αλλά δεν χαθεί (πρόωρη λήξη του χρονικού ορίου) ή η απόδειξη χαθεί, η επαναμετάδοση έχει ως αποτέλεσμα ένα διπλότυπο πακέτο στην πλευρά του παραλήπτη.

Σειριακός αριθμός
Χρησιμοποιείται για την διαδοχική αρίθμηση των πακέτων δεδομένων που μεταδίδονται από τον αποστολέα στον παραλήπτη. Τα κενά στους αριθμούς ακολουθίας των ληφθέντων πακέτων επιτρέπουν στον δέκτη να ανιχνεύσει την απώλεια πακέτων. Οι ίδιοι αριθμοί ακολουθίας των πακέτων σημαίνουν ότι τα πακέτα είναι διπλότυπα το ένα του άλλου.

Επιβεβαίωση
Δημιουργείται από το μέρος λήψης και υποδεικνύει στο μέρος αποστολής ότι το αντίστοιχο πακέτο ή ομάδα πακέτων έχει ληφθεί με επιτυχία. Συνήθως, η επιβεβαίωση περιέχει τους αριθμούς ακολουθίας των πακέτων που λήφθηκαν με επιτυχία. Ανάλογα με το πρωτόκολλο, γίνεται διάκριση μεταξύ ατομικών και ομαδικών επιβεβαιώσεων.

Αρνητική επιβεβαίωση
Χρησιμοποιείται από τον παραλήπτη για να ενημερώσει τον αποστολέα ότι το πακέτο ελήφθη εσφαλμένα. Μια αρνητική επιβεβαίωση συνήθως περιλαμβάνει τον αριθμό ακολουθίας του πακέτου που δεν ελήφθη σωστά.

Παράθυρο, αγωγός
Περιορίστε το εύρος των αριθμών ακολουθίας που μπορούν να χρησιμοποιηθούν για τη μετάδοση πακέτων. Οι μεταδόσεις multicast και handshake επιτρέπουν τη σημαντική αύξηση της απόδοσης των πρωτοκόλλων σε σύγκριση με τη λειτουργία αναμονής για επιβεβαιώσεις. Όπως θα δούμε, το μέγεθος του παραθύρου μπορεί να υπολογιστεί με βάση τις δυνατότητες λήψης και προσωρινής αποθήκευσης του λήπτη, καθώς και το επίπεδο φόρτου δικτύου.

Περισσότερα παραδείγματα δικτύωσης Go

В αποθετήρια.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο