
Neile, kes soovivad aru saada võrkudest ja protokollidest, on see pühendatud.
Lühidalt
Artiklis käsitletakse usaldusväärse andmeedastuse aluseid, tuues näiteid , sealhulgas UDP ja TCP kohta. Inspireeritud , , ja raamatust "Arvutivõrgud. Allavoolu lähenemine", sest kõik räägivad ainult Tanenbaumist ja Oliferist.
Transportprotokoll
tagab loogilise ühenduse rakendusprotsesside vahel, mis töötavad erinevates hostides. Rakenduseste jaoks näeb loogiline ühendus välja nagu kanal, mis ühendab protsessid otse.

toetavad lõpp-süsteemid, kuid mitte võrgu marsruutorid (välja arvatud — ). Saatja poolel muundab transporttase andmed rakendusastmest, mille ta saab edastavalt rakendusprotsessilt, transporttaseme pakettideks, mida nimetatakse segmentideks.

See toimub rakendusastme sõnumite vajadusel fragmenteerimise ja igaühe juurde transporttaseme päise lisamisega.

Seejärel edastab transporttase segmenti saatja võrgu tasandile, kus segment kapseldatakse võrgu tasandi paketti (datagrammi) ja saadetakse edasi. Vastuvõtva poole võrgu tase ekstraktsioonib transporttase segment datagrammist ja edastab selle üles transporttase. Edasi töötleb transporttase saadud segmenti nii, et selle andmed oleksid vastuvõtva rakenduse jaoks kergesti kättesaadavad.

Andmete usaldusväärse edastamise põhimõtted
Usaldusväärne andmete edastamine täiesti usaldusväärses kanalites
Lihtsaim juhtum. Saatja pool lihtsalt võtab andmed ülemiselt tasandilt, loob neid sisaldava paketi ja saadab selle kanalisse.
Server
package main
import (
"log"
"net"
)
func main() {
// Serveri IP-aadress ja port
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
if err != nil {
log.Fatal(err)
}
// Loome soketi koos portiga
serverConn, err := net.ListenUDP("udp", serverAddr)
if err != nil {
log.Fatal(err)
}
// Lükatakse ühenduse sulgemine edasi
defer serverConn.Close()
// Loome andmepuud
buf := make([]byte, 1024)
// Ootame ühendust
for {
// Loeme päringu
n, addr, err := serverConn.ReadFromUDP(buf)
// Edastame andmed ÜLEMINEKUKIHILE: meie puhul stdout
println(string(buf[0:n]), " form ", addr.IP.String())
if err != nil {
log.Fatal(err)
}
// Vastust ei ole, kuna see on UDP + usaldusväärne kanal
}
}Klient
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
// Serveri IP-aadress ja port
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
if err != nil {
log.Fatal(err)
}
// Kohalik IP-aadress ja port
localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
if err != nil {
log.Fatal(err)
}
// Ühenduse loomine
conn, err := net.DialUDP("udp", localAddr, serverAddr)
if err != nil {
log.Fatal(err)
}
// Ühenduse viivitamine sulgemine
defer conn.Close()
for {
// Andmete vastuvõtt ÜLEMINEKUTEST
fmt.Print("Sisestage lause > ")
var msg string
_, err := fmt.Scanf("%s", &msg)
if err != nil {
log.Fatal(err)
}
// Edastatakse baitide voog, mitte string
buf := []byte(msg)
// Kirjutamine (edastamine) ühendusse
_, err = conn.Write(buf)
if err != nil {
log.Fatal(err)
}
// Ootame natuke
time.Sleep(time.Second * 1)
}
}Usaldusväärne andmeedastus kanalil, kus võivad esineda vead
Järgmine etapp on eeldamine, et kõik edastatud paketid on saadud selles järjestuses, milles need saadeti, kuid nende bitid võivad olla kahjustatud, kuna kanalis edastatakse mõnikord andmeid moonutatult.

Sellisel juhul rakendatakse mehhanisme:
- vea tuvastamine;
- tagasiside;
- uuesti edastamine.
Usaldusväärse andmeedastuse protokollid, mis omavad sarnaseid mehhanisme andmeedastuse korduvaks taotlemiseks, nimetatakse automaatse korduvtaotluse protokollideks (Automatic Repeat reQuest, ARQ).
Lisaks tuleks arvestada ka vigade võimalusega kinnitustes, kui vastuvõtja ei saa mingit teavet viimase paketi edastamise tulemuste kohta.
Selle probleemi lahendamiseks, mis on kasutusel ka TCP-s, lisatakse andmepaketti uus väli, mis sisaldab paketi järjestusnumbrit.

Usaldusväärne andmeedastus usaldusväärselt kanali kaudu, mis võimaldab moonutusi ja pakettide kaotust.
Kahjuks kaasnevad moonutustega ka kaotatud paketid.
Ja selle probleemi lahendamiseks vajatakse mehhanisme:
- pakettide kaotuse määratlemiseks;
- kaotatud paketide uuesti edastamiseks vastuvõtjale.
Lisaks pakettide kaotusele tuleb arvestada võimalusega kaotada kviitung või, kui midagi ei ole kadunud, selle edastamisega olulise viivitusega. Kõigil juhtudel toimub sama asi: paketi uuesti edastamine. Aja kontrollimiseks kasutatakse selle mehhanismi raames taimerit, mis võimaldab määrata ooteaja lõpu. Nii on pakett. TCPKeepAlive parameeter on vaikimisi seadistatud 15 sekundiks.
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)Edastaval poolel tuleb iga kord paketi edastamisel (nii esmakordsel kui ka uuesti edastamisel) käivitada taimer, töödelda taimerist tingitud katkestusi ja peatada see.
Nii oleme tutvunud usaldusliku andmeedastuse protokollide põhikontseptsioonidega:
- kontrollsummadega;
- pakettide järjestusnumber;
- taimeritega;
- positiivsete ja negatiivsete kviitungitega.
Aga see pole veel kõik!
Usaldusliku andmeedastuse protokoll, mis toetab torujuhtmeid.
Selles variandis, mida oleme juba arutanud, on usalduslikkuse transportimise protokoll väga ebatõhus. See hakkab "pidurdama" edastamist, mida pakub sidekanal, RTT suurenedes. Selle tõhususe tõstmiseks ja sidekanali läbilaskvuse parema kasutamise jaoks rakendatakse konveierimist.

Konveierimise rakendamine toob kaasa:
- järjekorranumbrite arvu suurenemise, kuna kõik saadetavad paketid (kui mitte kordusülekanded) peavad olema üheselt tuvastatavad;
- vajaduse suurendada puhvermahte edastamise ja vastuvõtmise külgedel.
Järjekorranumbrite vahemik ja puhvermahtude nõudmised sõltuvad protokollist ning sellest, kuidas reageeritakse pärandile, pakettide kadumisele ja viivitusele. Konveierimise puhul on olemas kaks viga parandamise meetodit:
- tagasivõtmine N paketti tagasi;
- valikuline kordamine.
Tagasivõtmine N paketti tagasi — libiseva akna protokoll

Saatjal peab olema kolm tüüpi sündmuste jälgimine:
- ülemise taseme protokolli kutsumine. Kui ülemine tase kutsub üles andmete saatmise funktsiooni, kontrollib saatja esmalt akna täituvust (see tähendab, kas N saadetud sõnumit ootavad vastuvõtu kinnitust). Kui aken on täitmata, moodustatakse ja edastatakse uus pakett ning muutuja väärtused uuendatakse. Vastupidisel juhul edastab saatja andmed ülemisele tasemele, mis on vaikimisi märk sellest, et aken on täidetud. Üldiselt ülemine tase proovib andmete edastamist uuesti pärast mõnda aega. Reaalses rakenduses oleks saatja tõenäoliselt kas andmeid vahemälustanud (asemel koheselt saatmist) või oleks tal sünkroniseerimise mehhanism (nt semafor või lipp), mis võimaldaks ülemisel tasemel funktsiooni kutsuda ainult siis, kui aken on täitmata.
- kinnitatud vastuvõtmine. Protokollis antakse N järjekorranumbriga paketi kohta üldine kinnituskiri, mis näitab, et kõik pakettide järjekorranumbrid, mis eelnevad N-ile, on edukalt vastu võetud.
- истечение интервала ожидания. Для определения фактов потерь и задержек пакетов и квитанций протокол использует таймер. Если интервал ожидания истекает, передающая сторона повторно отправляет все посланные неподтвержденные пакеты.
Выборочное повторение
Когда размер окна и произведение пропускной способности на задержку распространения велики, в конвейере может находиться большое количество пакетов. В таком случае ошибка отдельного пакета может вызвать повторную передачу большого количества пакетов, большинство из которых не требовались.
Näide
Лучшие практики собраны в практической реализации . А если кто-то знает, как лучше — .
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"))
}
}Klient
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 {
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)
}
}Kokkuvõte
Mekanismid, mis tagavad usaldusväärse andmete edastamise ja nende kasutamise
Mehhanism
Rakendus, kommentaar
Kontrollsumma
Kasutatakse edastatud paketis bitivigade tuvastamiseks
Taimer
Ooteintervalli loendamine ja selle lõppemise näitamine. Viimane tähendab, et on tõenäoliselt pakett või selle kinnitamine edastamisel kadunud. Kui pakett toimetatakse viivitusega, kuid ei kao (ennatlik ooteintervalli lõpp), või toimub kinnitamise kadumine, siis uue edastamise tulemusel saab saamispoolel paketi dubleerimine.
Järjekorranumber
Kasutatakse andmepakettide järjestikuse numereerimise jaoks, mis edastatakse saatjalt saajale. Saadetud pakettide järjestikusnumbrite katkestused võimaldavad saajal avastada paketi kaotuse. Sama järjestikune number pakettides tähendab, et paketid dubleerivad üksteist.
Kinnitamine
Tegevuspool genereerib, näidates sellele, et vastav pakk või pakkide rühm on edukalt vastu võetud. Tüüpiliselt sisaldab kinnitamine edukalt vastu võetud pakkide järjestikuseid numbreid. Protokollist sõltuvalt eristatakse individuaalseid ja rühmakinnitamisi.
Negatiivne kinnitamine
Kasutatakse saaja poolt saatjale, et teavitada, et pakk on saanud vale. Negatiivne kinnitamine sisaldab tavaliselt paketi järjestikust numbrit, mis ei ole korrektset.
Aken, torustik
Piirab pakettide edastamiseks kasutatavate järjestikuse numbrite vahemikku. Rühmaedastus ja käepigistus võimaldavad märkimisväärselt suurendada protokollide läbilaskevõimet võrreldes kinnituste ooterežiimiga. Nagu näeme, saab akna suurust arvutada vastuvõtva poole vastuvõtu- ja vahemälufunktsioonide ning võrgu koormuse taseme põhjal.
Teised näited Go kasutamisest võrgu tööks
V .
Allikas: habr.com
