
Azoknak, akik Elkötelezett a hálózatok és protokollok megértése.
tömören
A cikk a megbízható adatátvitel alapjait tárgyalja, példákat mutat be , beleértve az UDP-t és a TCP-t. Alapján , , és a "Számítógépes hálózatok. Felülről lefelé irányuló megközelítés" című könyveket, különben mindenki csak Tannenbaumról és Oliferovról beszél.
Szállítási réteg protokoll
Logikai kapcsolatot biztosít a különböző gazdagépeken futó alkalmazási folyamatok között. Alkalmazás szempontjából a logikai kapcsolat olyan csatornának tűnik, amely közvetlenül összeköti a folyamatokat.

végrendszerek támogatják, de a hálózati útválasztók nem (kivéve - ). A küldő oldalon a szállítási réteg a küldő alkalmazási folyamattól kapott alkalmazási rétegadatokat szállítási rétegbeli csomagokká, úgynevezett szegmensekké alakítja át.

Ez úgy történik, hogy (ha szükséges) az alkalmazási réteg üzeneteit töredékekre bontja, és mindegyikhez hozzáad egy szállítási réteg fejlécet.

A szállítási réteg ezután átadja a szegmenst a küldő hálózati rétegének, ahol a szegmenst egy hálózati réteg csomagba (datagramba) zárják és elküldik. A fogadó oldalon a hálózati réteg kivonja a szállítási réteg szegmenst a datagramból, és továbbítja a szállítási rétegnek. Ezután a szállítási réteg feldolgozza a fogadott szegmenst, hogy az adatai elérhetővé váljanak a fogadó alkalmazás számára.

A megbízható adatátvitel elvei
Megbízható adatátvitel teljesen biztonságos csatornán
A legegyszerűbb eset. A küldő oldal egyszerűen fogadja az adatokat a felső rétegről, létrehoz egy csomagot, amely tartalmazza azokat, és elküldi a csatornának.
Сервер
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 + надежный канал
}
}vásárló
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)
}
}Megbízható adatátvitel csatornán keresztül lehetséges hibákkal
Következő lépésként feltételezzük, hogy az összes továbbított csomag vétele a küldés sorrendjében történik, de a bennük lévő bitek megsérülhetnek amiatt, hogy a csatorna időnként torzulva továbbít adatokat.

Ebben az esetben a következő mechanizmusokat használják:
- hibafelismerés;
- Visszacsatolás;
- újraközvetítés.
Azokat a megbízható adatátviteli protokollokat, amelyek hasonló mechanizmussal rendelkeznek az átvitel többszöri megismétlésére, automatikus ismétlési kérés (ARQ) protokolloknak nevezik.
Emellett érdemes figyelembe venni a vételi hibák lehetőségét, amikor a fogadó fél nem kap információt az utolsó csomag átvitelének eredményéről.
A TCP-ben is használt probléma megoldása az, hogy az adatcsomaghoz egy új mezőt adunk, amely tartalmazza a csomag sorszámát.

Megbízható adatátvitel megbízhatatlan csatornán, amely csomagtorzulásnak és -veszteségnek van kitéve
A torzítással együtt sajnos csomagvesztés is előfordul a hálózatban.
És a probléma megoldásához mechanizmusokra van szükség:
- a csomagvesztés tényének meghatározása;
- az elveszett csomagok újbóli kézbesítése a fogadó félnek.
Ezen túlmenően a csomag elvesztése mellett gondoskodni kell az átvételi elismervény elvesztésének lehetőségéről, vagy ha nem vész el, akkor jelentős késéssel történő kézbesítéséről. Minden esetben ugyanaz történik: a csomag újraküldésre kerül. Az idő szabályozására ez a mechanizmus egy visszaszámlálót használ, amely lehetővé teszi a várakozási intervallum végének meghatározását. Tehát a csomagban A TCPKeepAlive alapértelmezés szerint 15 másodpercre van állítva:
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)A küldő oldalnak minden egyes csomagküldéskor indítania kell egy időzítőt (mind az első, mind a második alkalommal), kezelnie kell az időzítő megszakításait és le kell állítania.
Így megismerkedtünk a megbízható adatátviteli protokollok kulcsfogalmaival:
- ellenőrző összegek;
- a csomagok sorszáma;
- időzítők;
- pozitív és negatív bevételek.
De ez még nem minden!
Megbízható adatátviteli protokoll csővezetékekkel
Az általunk már megvizsgált változatban a megbízható szállítási protokoll nagyon nem hatékony. Az RTT növekedésével elkezdi „lassítani” a kommunikációs csatorna által biztosított átvitelt. Hatékonyságának növelése és a kommunikációs csatorna kapacitásának jobb kihasználása érdekében csővezetéket alkalmaznak.

A csővezeték használata a következőkhöz vezet:
- a sorszámok tartományának növelése, mivel minden elküldött csomagot (kivéve az újraküldést) egyedileg azonosítani kell;
- a pufferek növelésének szükségessége az adó és a vevő oldalon.
A sorozatszám-tartomány és a pufferméret követelményei a protokoll által a csomagok sérülésére, elvesztésére és késleltetésére válaszul végrehajtott műveletektől függenek. Csővezetékezés esetén két módszer létezik a hibák kijavítására:
- N csomag visszaküldése;
- szelektív ismétlés.
Visszatérve N csomag – csúszó ablak protokoll

A feladónak három eseménytípust kell támogatnia:
- magasabb szintű protokollal hívja. Amikor az adatküldő funkciót „felülről” hívjuk, a küldő oldal először az ablak kitöltöttségét (vagyis N darab nyugtára váró üzenet meglétét) ellenőrzi. Ha az ablak üres, a rendszer új csomagot generál és továbbít, és frissíti a változó értékeket. Ellenkező esetben a küldő oldal visszaküldi az adatokat a felső rétegnek, és ez implicit jelzi, hogy az ablak megtelt. Általában a felső réteg egy idő után újra megpróbálja továbbítani az adatokat. Valós alkalmazásban a küldő valószínűleg vagy pufferelné az adatokat (ahelyett, hogy azonnal elküldené), vagy van egy szinkronizálási mechanizmusa (például egy szemafor vagy zászló), amely lehetővé teszi a felső réteg számára, hogy csak akkor hívja meg a küldési funkciót, ha az ablak üres. .
- megerősítést kap. A protokollban az N sorszámú csomagra általános nyugtázást adnak ki, amely jelzi, hogy az összes N előtti sorszámú csomagot sikeresen fogadták.
- a várakozási idő lejárt. A csomagok és bevételek elvesztésének és késésének tényeinek meghatározásához a protokoll időzítőt használ. Ha az időkorlát lejár, a küldő oldal újra elküldi az összes elküldött nyugtázatlan csomagot.
Szelektív ismétlés
Ha az ablak mérete és az átviteli sebesség-terjedés késleltetési szorzata nagy, nagyszámú csomag lehet folyamatban. Ilyen esetben egyetlen csomaghiba nagy számú csomag újraküldését okozhatja, amelyek többségére nem volt szükség.
Példa
Felső gyakorlatok összegyűjtése a gyakorlati megvalósítás során . És ha valaki tudja, hogyan a legjobb... .
Сервер
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"))
}
}vásárló
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)
}
}Teljesítmény
A megbízható adatátvitelt és -használatot biztosító mechanizmusok
Механизм
Jelentkezés, hozzászólás
Ellenőrző összeg
A továbbított csomagban lévő bithibák észlelésére szolgál
időzítő
Visszaszámolja az időtúllépési intervallumot, és jelzi, ha lejárt. Ez utóbbi azt jelenti, hogy nagy valószínűséggel a csomag vagy annak vétele elveszik az átvitel során. Ha egy csomagot késéssel kézbesítenek, de nem vesznek el (az időtúllépési idő idő előtti lejárta), vagy egy nyugta elveszik, az újraküldés a fogadó oldalon duplikált csomaghoz vezet.
Sorozatszám
A feladótól a címzettig továbbított adatcsomagok sorszámozására szolgál. A fogadott csomagok sorszámának hézagai lehetővé teszik a vevő számára a csomagvesztés észlelését. Az azonos csomagsorszámok azt jelentik, hogy a csomagok egymás másolatai
megerősítés
A fogadó vég generálja, és jelzi a küldő végnek, hogy a megfelelő csomag vagy csomagcsoport sikeresen vétele megtörtént. A nyugtázás jellemzően a sikeresen fogadott csomagok sorszámát tartalmazza. A protokolltól függően egyéni és csoportos megerősítéseket különböztetnek meg
Negatív megerősítés
A címzett arra használja, hogy tájékoztassa a feladót, hogy a csomag hibásan érkezett. A negatív nyugtázás általában a nem megfelelően fogadott csomag sorszámát tartalmazza
Ablak, szállítószalag
Korlátozza a csomagok továbbítására használható sorszámok tartományát. A csoportos küldés és a kézfogás jelentősen megnövelheti a protokoll átviteli sebességét a nyugtázásra való várakozáshoz képest. Amint látni fogjuk, az ablak mérete a fogadó oldal vételi és pufferelési képességei, valamint a hálózat terhelési szintje alapján számítható ki.
További példák a Go hálózati használatára
В .
Forrás: will.com
