Onima koji
ukratko
Članak govori o osnovama pouzdanog prijenosa podataka, implementira primjere
Protokol transportnog sloja
Pruža logičku vezu između aplikacijskih procesa koji se izvode na različitim hostovima. Iz perspektive aplikacije, logička veza izgleda kao kanal koji izravno povezuje procese.
To se postiže dijeljenjem (ako je potrebno) poruka aplikacijskog sloja u fragmente i dodavanjem zaglavlja transportnog sloja svakom od njih.
Prijenosni sloj zatim prosljeđuje segment mrežnom sloju pošiljatelja, gdje se segment enkapsulira u paket mrežnog sloja (datagram) i šalje. Na prijemnom kraju, mrežni sloj izdvaja segment transportnog sloja iz datagrama i prosljeđuje ga transportnom sloju. Zatim, prijenosni sloj obrađuje primljeni segment tako da njegovi podaci postaju dostupni aplikaciji primateljici.
Načela pouzdanog prijenosa podataka
Pouzdan prijenos podataka preko potpuno sigurnog kanala
Najjednostavniji slučaj. Strana koja šalje podatke jednostavno prima podatke s gornjeg sloja, kreira paket koji ih sadrži i šalje ih 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 prijenos podataka putem kanala s mogućim pogreškama
Sljedeći korak je pretpostaviti da su svi poslani paketi primljeni redoslijedom kojim su poslani, ali bitovi u njima mogu biti oštećeni zbog činjenice da kanal ponekad prenosi podatke s izobličenjima.
U ovom slučaju koriste se sljedeći mehanizmi:
- otkrivanje grešaka;
- Povratne informacije;
- retransmisija.
Pouzdani protokoli za prijenos podataka koji imaju slične mehanizme za višestruko ponavljanje prijenosa nazivaju se protokoli za automatski zahtjev za ponavljanjem (ARQ).
Osim toga, vrijedi razmotriti mogućnost pogrešaka u primicima, kada primatelj neće primiti nikakve informacije o rezultatima prijenosa posljednjeg paketa.
Rješenje ovog problema, koje se također koristi u TCP-u, je dodavanje novog polja paketu podataka koje sadrži redni broj paketa.
Pouzdan prijenos podataka preko nepouzdanog kanala podložnog izobličenju i gubitku paketa
Uz distorziju, 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 primatelju.
Dodatno, osim gubitka paketa, potrebno je predvidjeti mogućnost gubitka računa ili, ako ništa nije izgubljeno, njegove dostave sa značajnim kašnjenjem. U svim slučajevima radi se ista stvar: paket se ponovno šalje. Za kontrolu vremena ovaj mehanizam koristi mjerač vremena koji vam omogućuje određivanje kraja 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 mora pokrenuti mjerač vremena svaki put kada se paket odašilje (i prvi i drugi put), obraditi prekide mjerača vremena i zaustaviti ga.
Dakle, upoznali smo se s ključnim konceptima pouzdanih protokola za prijenos podataka:
- kontrolni zbrojevi;
- redni brojevi paketa;
- mjerači vremena;
- pozitivnih i negativnih primitaka.
Ali to nije sve!
Pouzdan protokol prijenosa podataka s cjevovodom
U varijanti koju smo već razmotrili, pouzdani protokol isporuke je vrlo neučinkovit. Počinje "usporavati" prijenos koji pruža komunikacijski kanal kako se RTT povećava. Kako bi se povećala njegova učinkovitost i bolje iskoristio kapacitet komunikacijskog kanala, koristi se cjevovod.
Korištenje cjevovoda dovodi do:
- povećanje raspona rednih brojeva, budući da svi poslani paketi (osim ponovnih prijenosa) moraju biti jedinstveno identificirani;
- potreba za povećanjem međuspremnika na odašiljačkoj i prijamnoj strani.
Raspon sekvencijskih brojeva i zahtjevi za veličinom međuspremnika ovise o radnjama koje protokol poduzima kao odgovor na oštećenje paketa, gubitak i kašnjenje. U slučaju cjevovoda, postoje dvije metode za ispravljanje pogrešaka:
- vratiti N paketa natrag;
- selektivno ponavljanje.
Povratak N paketa - protokol kliznog prozora
Pošiljatelj mora podržavati tri vrste događaja:
- poziv protokolom više razine. Kada se funkcija slanja podataka pozove "odozgo", strana koja šalje prvo provjerava stupanj popunjenosti prozora (to jest, prisutnost N poslanih poruka koje čekaju primitak potvrda). Ako je prozor prazan, novi paket se generira i šalje, a vrijednosti varijable se ažuriraju. Inače, strana pošiljatelj vraća podatke na gornji sloj, a to je implicitna indikacija da je prozor pun. Obično će gornji sloj ponovno pokušati prenijeti podatke nakon nekog vremena. U stvarnoj aplikaciji, pošiljatelj bi vjerojatno ili spremio podatke u međuspremnik (umjesto da ih odmah pošalje) ili bi imao mehanizam sinkronizacije (kao što je semafor ili zastavica) koji bi omogućio gornjem sloju da pozove funkciju slanja samo kada je prozor prazan .
- primanje potvrde. U protokolu, za paket s rednim brojem N izdaje se opća potvrda koja pokazuje da su svi paketi s rednim brojevima ispred N uspješno primljeni.
- interval čekanja je istekao. Za utvrđivanje činjenica o gubicima i kašnjenjima paketa i primitaka, protokol koristi mjerač vremena. Ako interval istekne, pošiljateljska strana ponovno šalje sve poslane nepotvrđene pakete.
Selektivno ponavljanje
Kada su veličina prozora i produkt kašnjenja širenja propusnosti veliki, veliki broj paketa može biti u cjevovodu. U takvom slučaju, pogreška jednog paketa može uzrokovati ponovni prijenos velikog broja paketa, od kojih većina nije bila potrebna.
Primjer
Vrh
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)
}
}
Izlaz
Mehanizmi koji osiguravaju pouzdan prijenos i korištenje podataka
mehanizam
Prijava, komentar
Kontrolna svota
Koristi se za otkrivanje pogrešaka u bitovima u poslanom paketu
brojač
Odbrojava interval čekanja i pokazuje kada je istekao. Potonje znači da je s velikim stupnjem vjerojatnosti paket ili njegova potvrda izgubljena tijekom prijenosa. Ako je paket isporučen s odgodom, ali nije izgubljen (prerano istekao vremenski interval) ili je potvrda izgubljena, ponovni prijenos dovodi do dupliciranog paketa na strani primatelja
Serijski broj
Koristi se za sekvencijalno numeriranje paketa podataka koji se prenose od pošiljatelja do primatelja. Praznine u rednim brojevima primljenih paketa omogućuju primatelju da otkrije gubitak paketa. Isti redni brojevi paketa znače da su paketi duplikati jedan drugoga
Potvrda
Generira ga primatelj i pokazuje pošiljatelju da je odgovarajući paket ili grupa paketa uspješno primljena. Obično potvrda sadrži redne brojeve uspješno primljenih paketa. Ovisno o protokolu razlikuju se pojedinačne i grupne potvrde
Negativna potvrda
Koristi ga primatelj da obavijesti pošiljatelja da je paket pogrešno primljen. Negativna potvrda obično uključuje redni broj paketa koji nije ispravno primljen
Prozor, pokretna traka
Ograničite raspon rednih brojeva koji se mogu koristiti za prijenos paketa. Multicast i rukovanje mogu značajno povećati protok protokola u usporedbi s čekanjem potvrde. Kao što ćemo vidjeti, veličina prozora može se izračunati na temelju mogućnosti prijema i međuspremnika primatelja, kao i razine opterećenja mreže
Više primjera korištenja Go za umrežavanje
В
Izvor: www.habr.com