Azoknak, akik
tömören
A cikk a megbízható adatátvitel alapjait tárgyalja, példákat mutat be
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.
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
// 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ő
Сервер
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