Onima koji
Ukratko
Članak govori o osnovama pouzdanog prijenosa podataka, implementira primjere na
Protokol transportnog sloja
Pruža logičku vezu između procesa aplikacije koji se pokreću na različitim hostovima. Iz perspektive aplikacije, logička veza izgleda kao kanal koji direktno povezuje procese.
Ovo se radi cijepanjem (ako je potrebno) poruka sloja aplikacije na fragmente i dodavanjem zaglavlja transportnog sloja svakom od njih.
Transportni sloj zatim prosljeđuje segment na mrežni sloj pošiljatelja, gdje se segment inkapsulira u paket mrežnog sloja (datagram) i šalje. Na kraju prijema, mrežni sloj izdvaja segment transportnog sloja iz datagrama i prosljeđuje ga transportnom sloju. Zatim, transportni sloj obrađuje primljeni segment tako da njegovi podaci postaju dostupni aplikaciji koja prima.
Principi pouzdanog prenosa podataka
Pouzdan prenos podataka preko potpuno bezbednog kanala
Najjednostavniji slučaj. Strana koja šalje podatke jednostavno prima podatke od gornjeg sloja, kreira paket koji ih sadrži i šalje ga kanalu.
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 + надежный канал
}
}
Kupac
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)
}
}
Pouzdan prenos podataka preko kanala sa mogućim greškama
Sljedeći korak je pretpostaviti da se svi poslani paketi primaju redoslijedom kojim su poslani, ali bitovi u njima mogu biti oštećeni zbog činjenice da kanal ponekad prenosi podatke sa izobličenjem.
U ovom slučaju koriste se sljedeći mehanizmi:
- detekcija grešaka;
- povratne informacije;
- retransmisija.
Pouzdani protokoli za prijenos podataka koji imaju slične mehanizme za ponavljanje prijenosa više puta nazivaju se protokoli zahtjeva za automatsko ponavljanje (ARQ).
Osim toga, vrijedno je razmotriti mogućnost grešaka u prijemu, kada strana koja prima neće dobiti nikakvu informaciju o rezultatima prijenosa posljednjeg paketa.
Rješenje ovog problema, koje se također koristi u TCP-u, je dodavanje novog polja u paket podataka koje sadrži redni broj paketa.
Pouzdan prenos podataka preko nepouzdanog kanala podložan izobličenju i gubitku paketa
Uz izobličenje, nažalost, dolazi i do gubitka paketa u mreži.
A za rješavanje ovog problema potrebni su mehanizmi:
- utvrđivanje činjenice gubitka paketa;
- ponovna dostava izgubljenih paketa strani primaocu.
Dodatno, pored gubitka paketa, potrebno je predvidjeti mogućnost gubitka računa ili, ako ništa nije izgubljeno, njegovu dostavu sa značajnim zakašnjenjem. U svim slučajevima radi se ista stvar: paket se ponovo prenosi. Za kontrolu vremena, ovaj mehanizam koristi tajmer za odbrojavanje, koji vam omogućava da odredite kraj intervala čekanja. Dakle u paketu
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)
Strana koja šalje treba da pokrene tajmer svaki put kada se paket prenese (i prvi i drugi put), obradi prekide tajmera i zaustavi ga.
Dakle, upoznali smo se s ključnim konceptima pouzdanih protokola za prijenos podataka:
- kontrolne sume;
- redni brojevi paketa;
- tajmeri;
- pozitivne i negativne račune.
Ali to nije sve!
Pouzdan protokol za prijenos podataka s cjevovodom
U varijanti koju smo već razmatrali, pouzdan protokol isporuke je vrlo neefikasan. Počinje da „usporava“ prenos koji obezbeđuje komunikacijski kanal kako se RTT povećava. Da bi se povećala njegova efikasnost i bolje iskoristio kapacitet komunikacijskog kanala, koristi se cjevovod.
Upotreba cjevovoda dovodi do:
- povećanje opsega redoslednih brojeva, pošto svi poslani paketi (osim retransmisije) moraju biti jedinstveno identifikovani;
- potreba za povećanjem bafera na strani koja prenosi i prima.
Zahtjevi za raspon brojeva sekvence i veličinu bafera zavise od akcija koje protokol poduzima kao odgovor na oštećenje, gubitak i kašnjenje paketa. U slučaju cjevovoda, postoje dvije metode za ispravljanje grešaka:
- vratiti N paketa nazad;
- selektivno ponavljanje.
Povratak N paketa - protokol kliznog prozora
Pošiljalac mora podržavati tri vrste događaja:
- poziva po protokolu višeg nivoa. Kada se funkcija slanja podataka pozove „odozgo“, strana koja šalje prvo proverava stepen popunjenosti prozora (tj. prisustvo N poslanih poruka koje čekaju prijem potvrda). Ako je prozor prazan, novi paket se generira i prenosi, a vrijednosti varijabli se ažuriraju. U suprotnom, strana koja šalje podatke vraća podatke u gornji sloj, a to je implicitna indikacija da je prozor pun. Obično će gornji sloj pokušati ponovo prenijeti podatke nakon nekog vremena. U stvarnoj aplikaciji, pošiljalac bi vjerovatno ili baferovao podatke (umjesto da ih odmah pošalje) ili bi imao mehanizam sinhronizacije (kao što je semafor ili zastavica) koji bi omogućio gornjem sloju da pozove funkciju slanja samo kada je prozor prazan .
- prima potvrdu. U protokolu, za paket sa rednim brojem N, izdaje se opšta potvrda koja pokazuje da su svi paketi sa rednim brojevima koji prethode N uspešno primljeni.
- interval čekanja je istekao. Za utvrđivanje činjenica gubitaka i kašnjenja paketa i prijema, protokol koristi tajmer. Ako istekne vremensko ograničenje, strana koja šalje ponovo šalje sve poslane nepotvrdjene pakete.
Selektivno ponavljanje
Kada su veličina prozora i proizvod kašnjenja propusnosti-propagacije veliki, veliki broj paketa može biti u cjevovodu. U takvom slučaju, greška u jednom paketu može uzrokovati ponovni prijenos velikog broja paketa, od kojih većina nije bila potrebna.
Primjer:
Lučšie
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"))
}
}
Kupac
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)
}
}
zaključak
Mehanizmi koji osiguravaju pouzdan prijenos i korištenje podataka
Mehanizam
Prijava, komentar
Čekovni zbroj
Koristi se za otkrivanje grešaka bitova u prenesenom paketu
Tajmer
Odbrojava vremenski interval i pokazuje kada je istekao. Ovo poslednje znači da se sa velikim stepenom verovatnoće paket ili njegov prijem izgubi tokom prenosa. Ako je paket isporučen sa zakašnjenjem, ali nije izgubljen (prerano istekao interval vremenskog ograničenja), ili je račun izgubljen, ponovni prijenos vodi do duplikata paketa na strani primaoca
Serijski broj
Koristi se za sekvencijalno numerisanje paketa podataka koji se prenose od pošiljaoca do primaoca. Praznine u redoslijedu primljenih paketa omogućavaju primaocu da otkrije gubitak paketa. Isti redni brojevi paketa znače da su paketi duplikati jedan drugog
Potvrda
Generirano od strane primaoca i ukazuje na kraj koji šalje da je odgovarajući paket ili grupa paketa uspješno primljena. Obično potvrda sadrži redovne brojeve uspješno primljenih paketa. U zavisnosti od protokola, razlikuju se pojedinačne i grupne potvrde
Negativna potvrda
Koristi se od strane primaoca da obavesti pošiljaoca da je paket pogrešno primljen. Negativna potvrda obično uključuje redni broj paketa koji nije ispravno primljen
Prozor, transportna traka
Ograničite raspon brojeva sekvence koji se mogu koristiti za prijenos paketa. Multicast i rukovanje mogu značajno povećati protok protokola u poređenju sa čekanjem na potvrde. Kao što ćemo vidjeti, veličina prozora se može izračunati na osnovu mogućnosti prijema i baferiranja na prijemnoj strani, kao i na nivou opterećenja mreže
Više primjera korištenja Go za umrežavanje
В
izvor: www.habr.com