Fir déi, déi
Kuerz gefrot
Den Artikel diskutéiert d'Basis vun zouverléissege Dateniwwerdroung, implementéiert Beispiller op
Transport Layer Protokoll
Bitt eng logesch Verbindung tëscht Applikatiounsprozesser déi op verschiddene Hosten lafen. Aus enger Applikatiounsperspektiv gesäit eng logesch Verbindung aus wéi e Kanal deen Prozesser direkt verbënnt.
Dëst gëtt gemaach andeems Dir (wann néideg) d'Applikatiounsschicht Messagen a Fragmenter opdeelt an en Transportschichtheader un all eenzel bäidréit.
D'Transportschicht passéiert dann de Segment un d'Netzschicht vum Sender, wou de Segment an engem Netzwierkschichtpaket (Datagram) agespaart gëtt a geschéckt gëtt. Um Empfangsend extrahéiert d'Netzschicht den Transportschichtsegment aus dem Datagram a passéiert et op d'Transportschicht. Als nächst veraarbecht d'Transportschicht de kritt Segment sou datt seng Donnéeën zur Empfangsapplikatioun verfügbar sinn.
Prinzipien vun zouverlässeg Daten Transmissioun
Zouverlässeg Dateniwwerdroung iwwer e komplett séchere Kanal
Am einfachsten Fall. D'Sendsäit kritt einfach d'Donnéeën vun der ieweschter Schicht, erstellt e Paket deen et enthält a schéckt se op de Kanal.
Server
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 + надежный канал
}
}
Client
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)
}
}
Zouverlässeg Dateniwwerdroung iwwer e Kanal mat méigleche Feeler
De nächste Schrëtt ass unzehuelen datt all iwwerdroe Pakete an der Uerdnung opgeholl ginn an där se geschéckt goufen, awer d'Bits an hinnen kënne korrupt sinn wéinst der Tatsaach datt de Kanal heiansdo Daten mat Verzerrungen iwwerdréit.
An dësem Fall ginn déi folgend Mechanismen benotzt:
- Feeler Detektioun;
- Feedback;
- retransmission.
Zouverlässeg Datenübertragungsprotokoller déi ähnlech Mechanismen hunn fir d'Transmissioun méi Mol ze widderhuelen, ginn Automatesch Repeat reQuest (ARQ) Protokoller genannt.
Zousätzlech ass et derwäert ze berücksichtegen d'Méiglechkeet vu Feeler an den Empfangen, wann d'Empfänger keng Informatioun iwwer d'Resultater vum Transfert vum leschte Paket kritt.
D'Léisung fir dëse Problem, och am TCP benotzt, ass en neit Feld un den Datepaket ze addéieren deen d'Sequenznummer vum Paket enthält.
Zuverlässeg Dateniwwerdroung iwwer en onzouverlässeg Kanal ënnerleien Paketverzerrung a Verloscht
Zesumme mat Verzerrung gëtt et leider Paketverloscht am Netz.
A fir dëse Problem ze léisen, sinn Mechanismen néideg:
- Bestëmmung vun der Tatsaach vum Paketverloscht;
- Re-Liwwerung vu verluerene Päckchen un déi empfaang Partei.
Zousätzlech, zousätzlech zum Verloscht vum Package, ass et néideg fir d'Méiglechkeet vum Verloscht vum Empfang ze garantéieren oder, wann näischt verluer ass, seng Liwwerung mat engem wesentleche Verspéidung. An alle Fäll gëtt datselwecht gemaach: de Paket gëtt nei iwwerdroen. Fir d'Zäit ze kontrolléieren, benotzt dëse Mechanismus e Countdown Timer, deen Iech erlaabt d'Enn vum Waardeintervall ze bestëmmen. Also am Package
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)
D'Sendsäit muss en Timer starten all Kéier wann e Paket iwwerdroe gëtt (souwuel déi éischt an déi zweet Kéier), Ënnerbriechungen vum Timer handhaben a stoppen.
Also hu mir d'Schlësselkonzepter vun zouverléissege Datentransferprotokoller vertraut:
- Kontrollsummen;
- Sequenznummeren vu Packagen;
- Timer;
- positiv an negativ Recetten.
Mee dat ass net alles!
Zouverlässeg Datenübertragungsprotokoll mat Pipelining
An der Variant, déi mir scho berücksichtegt hunn, ass den zouverléissege Liwwerprotokoll ganz ineffizient. Et fänkt un d'Transmissioun vun der Kommunikatiounskanal ze "verlueren" wéi d'RTT eropgeet. Fir seng Effizienz ze erhéijen an d'Kommunikatiounskanalkapazitéit besser ze notzen, gëtt Pipelining benotzt.
D'Benotzung vu Pipelining féiert zu:
- d'Erhéijung vun der Palette vun de Sequenznummeren, well all geschéckt Pakete (ausser fir Retransmissionen) muss eenzegaarteg identifizéiert ginn;
- de Besoin fir Puffer op der Sender- an Empfangssäit ze erhéijen.
D'Sequenznummerberäich an d'Puffergréisst Ufuerderunge hänkt vun den Aktiounen of, déi de Protokoll hëlt an Äntwert op Paketkorruptioun, Verloscht a Verzögerung. Am Fall vu Pipelining ginn et zwou Methoden fir Feeler ze korrigéieren:
- zréck N Pakete zréck;
- selektiv Widderhuelung.
Zréckgoen N Pakete - rutscht Fënster Protokoll
De Sender muss dräi Aarte vun Eventer ënnerstëtzen:
- ruffen mat engem méi héije Protokoll. Wann d'Date-Sendfunktioun "vun uewen" genannt gëtt, iwwerpréift d'Sendsäit fir d'éischt de Füllgrad vun der Fënster (dat ass d'Präsenz vun N geschéckte Messagen déi op d'Empfang vun de Empfang waarden). Wann d'Fënster eidel ass, gëtt en neie Paket generéiert an iwwerdroen, an d'Variabel Wäerter ginn aktualiséiert. Soss gëtt d'Send Säit Daten op déi iewescht Schicht zréck, an dëst ass eng implizit Indikatioun datt d'Fënster voll ass. Normalerweis probéiert déi iewescht Schicht d'Donnéeën no enger Zäit erëm ze vermëttelen. An enger realer Applikatioun wäert de Sender wahrscheinlech entweder d'Daten bufferen (amplaz se direkt ze schécken) oder e Synchroniséierungsmechanismus hunn (wéi e Semaphore oder Fändel) deen et erlaabt datt déi iewescht Schicht d'Sendfunktioun nëmmen ruffe wann d'Fënster eidel ass .
- kréien Confirmatiouns. Am Protokoll, fir e Paket mat der Sequenznummer N, gëtt eng allgemeng Unerkennung erausginn, déi beweist datt all Pakete mat Sequenznummeren viru N erfollegräich opgeholl goufen.
- d'Waardeintervall ass ofgelaf. Fir d'Fakten vu Verloschter a Verspéidungen vu Paketen a Empfangen ze bestëmmen, benotzt de Protokoll en Timer. Wann den Timeout-Intervall ofleeft, schéckt d'Sendsäit all geschéckt net unerkannt Pakete nei.
Selektiv Widderhuelung
Wann d'Fënstergréisst an d'Duerchgang-Verbreedungsverzögerungsprodukt grouss sinn, kann eng grouss Zuel vu Päck an der Pipeline sinn. An esou engem Fall kann en eenzege Paketfehler verursaachen datt eng grouss Zuel vu Pakete weidergeleet ginn, déi meescht vun deenen net erfuerderlech waren.
Beispill:
Déi bescht
Server
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"))
}
}
Client
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)
}
}
Konklusioun
Mechanismen fir zouverlässeg Datentransfer a Gebrauch ze garantéieren
Механизм
Bewerbung, Kommentar
Zomm kontrolléieren
Benotzt fir Bitfehler an engem iwwerdroe Paket z'entdecken
Timer
Zielt den Timeout-Intervall erof a weist un wéini et ofgelaf ass. Dat lescht bedeit datt mat engem héije Grad vu Wahrscheinlechkeet de Pak oder seng Empfang während der Iwwerdroung verluer geet. Wann e Paket mat enger Verzögerung geliwwert gëtt, awer net verluer ass (virzäitegen Oflaf vum Timeout-Intervall), oder e Empfang verluer ass, féiert d'Wiedertransmissioun zu engem Duplikat Paket op der Empfangssäit
Seriennummer
Benotzt fir sequentiell Nummeréierung vun Datepäck, déi vum Sender un den Empfänger iwwerdroe ginn. Lücken an der Sequenznummeren vun de empfangene Pakete erlaben den Empfänger Paketverloscht z'entdecken. Déi selwecht Paket Sequenznummeren bedeiten datt d'Päck Duplikate vuneneen sinn
Bestätegung
Generéiert vum Empfangsend a beweist dem Sendend Enn datt de entspriechende Paket oder Grupp vu Paketen erfollegräich opgeholl gouf. Typesch enthält d'Unerkennung d'Sequenznummeren vun erfollegräich empfangene Pakete. Ofhängeg vum Protokoll ginn individuell a Grupp Bestätegungen ënnerscheet
Negativ Bestätegung
Benotzt vum Empfänger fir de Sender z'informéieren datt de Paket falsch opgeholl gouf. Eng negativ Unerkennung enthält normalerweis d'Sequenznummer vum Paket deen net korrekt kritt gouf
Fënster, conveyorization
Limitéiert d'Gamme vu Sequenznummeren déi benotzt kënne fir Päck ze vermëttelen. Multicast an Handshake kënnen de Protokollduerchgang wesentlech erhéijen am Verglach zum Waarden op Unerkennungen. Wéi mir wäerte gesinn, kann d'Fënstergréisst berechent ginn op Basis vun den Empfangs- a Pufferfäegkeeten vum Empfangsend, souwéi dem Netzbelaaschtungsniveau
Méi Beispiller fir Go fir Netzwierker ze benotzen
В
Source: will.com