
Till dem som vill förstÄ nÀtverk och protokoll.
Kortfattat
Denna artikel behandlar grunderna för sÀker datatransmission och tillhandahÄller exempel pÄ , inklusive UDP och TCP. Inspirerat av , , och boken "Computer Networks. Nedtill upp-ansats", eftersom alla bara diskuterar Tanenbaum och Olifer.
Transportprotokoll
Ger en logisk anslutning mellan applikationsprocesser som körs pÄ olika vÀrdar. En logisk anslutning, frÄn applikationernas perspektiv, framstÄr som en kanal som direkt kopplar samman processerna.

underhĂ„lls av slutliga system men inte av nĂ€tverksroutrar (utom â ). PĂ„ avsĂ€ndarsidan omvandlar transportlagret de applikationsdata som mottas frĂ„n den skickande applikationsprocessen till transportnivĂ„paket, kallade segment.

Detta görs genom att dela upp (vid behov) applikationsmeddelanden i fragment och lÀgga till en transportlagersrubrik till varje.

DÀrefter överför transportlagret segmentet till avsÀndarens nÀtverksnivÄ, dÀr segmentet inkapslas i ett nÀtverksnivÄpaket (datagram) och skickas. PÄ mottagarsidan hÀmtar nÀtverksnivÄn transportlagssegmentet frÄn datagrammet och överför det uppÄt till transportlagret. Sedan bearbetar transportlagret det mottagna segmentet sÄ att dess data blir tillgÀngliga för mottagarens applikation.

Principer för sÀker datatransmission
SÀker datatransmission över en helt pÄlitlig kanal
Det enklaste fallet. AvsÀndarsidan tar helt enkelt emot data frÄn övre lagret, skapar ett paket som innehÄller dem och skickar det genom kanalen.
Servern
package main
import (
"log"
"net"
)
func main() {
\\ Serverns IP-adress och port
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
if err != nil {
log.Fatal(err)
}
\\ Skapa en socket med porten
serverConn, err := net.ListenUDP("udp", serverAddr)
if err != nil {
log.Fatal(err)
}
\\ Fördröjd stÀngning av anslutningen
defer serverConn.Close()
\\ Skapa en buffert för data
buf := make([]byte, 1024)
\\ VÀnta pÄ anslutning
for {
\\ LÀs förfrÄgan
n, addr, err := serverConn.ReadFromUDP(buf)
\\ Skicka data till ĂVRE nivĂ„n: i vĂ„rt fall stdout
println(string(buf[0:n]), " form ", addr.IP.String())
if err != nil {
log.Fatal(err)
}
\\ Det finns inget svar eftersom det Àr UDP + en pÄlitlig kanal
}
}Klient
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
\\ Serverns IP-adress och port
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
if err != nil {
log.Fatal(err)
}
\\ Lokal IP-adress och port
localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
if err != nil {
log.Fatal(err)
}
\\ StÀll in anslutning
conn, err := net.DialUDP("udp", localAddr, serverAddr)
if err != nil {
log.Fatal(err)
}
\\ Fördröjd stÀngning av anslutningen
defer conn.Close()
for {
\\ Ta emot data frĂ„n ĂVRE nivĂ„n
fmt.Print("Ange en fras > ")
var msg string
_, err := fmt.Scanf("%s", &msg)
if err != nil {
log.Fatal(err)
}
\\ Ström av bytes skickas, inte strÀng
buf := []byte(msg)
\\ Skriv (skicka) till anslutningen
_, err = conn.Write(buf)
if err != nil {
log.Fatal(err)
}
\\ VĂ€nta en sekund
time.Sleep(time.Second * 1)
}
}PÄlitlig dataöverföring över en kanal med potentiella fel
NÀsta steg Àr att anta att alla sÀnda paket har mottagits i den ordning de skickades, men bitarna kan vara skadade, eftersom kanalen ibland överför data med förvrÀngningar.

I sÄdana fall tillÀmpas mekanismer:
- felupptÀckning;
- Äterkoppling;
- Äteröverföring.
Protokoll för pÄlitlig dataöverföring, som har sÄdana mekanismer för upprepning av överföring, kallas protokoll med automatisk begÀran om Äteröverföring (Automatic Repeat reQuest, ARQ).
Dessutom bör man beakta möjligheten för fel i kvittenserna, nÀr mottagarsidan inte fÄr nÄgon information om resultatet av överföringen av det senaste paketet.
Lösningen pÄ denna uppgift, som Àven anvÀnds i TCP, Àr att lÀgga till ett nytt fÀlt med paketdata som innehÄller sekvensnummer för paketet.

Tillförlitlig dataöverföring över en opÄlitlig kanal som kan orsaka förvrÀngning och paketförlust
TyvÀrr förekommer paketförlust i nÀtverket samtidigt som förvrÀngningar.
Och för att lösa detta problem krÀvs mekanismer:
- för att identifiera paketförlust;
- Äterleverans av förlorade paket till mottagarsidan.
Utöver paketförlusten mÄste man Àven övervÀga möjligheten av kvittotabort, eller om inget har förlorats, att kvittot levereras med betydande fördröjning. I alla fall görs samma sak: paketet sÀnds om. För att kontrollera tiden i denna mekanism anvÀnds en nedrÀknare som möjliggör att faststÀlla slutet av vÀntetiden. SÄ i paketet Àr TCPKeepAlive-parametern som standard instÀlld pÄ 15 sekunder:
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)AvsÀndarsidan mÄste starta nedrÀknaren varje gÄng ett paket sÀnds (bÄde vid första och Äterleverans), hantera avbrott frÄn nedrÀknaren och stoppa den.
SÄ vi har blivit bekanta med de viktigaste begreppen för protokoll för pÄlitlig dataöverföring:
- kontrollsummor;
- paketordningsnummer;
- timers;
- positiva och negativa kvitton.
Men det Àr inte allt!
Protokoll för pÄlitlig dataöverföring med pipelining
I det alternativ som vi redan har granskat Àr protokollet för pÄlitlig leverans mycket ineffektivt. Det börjar "sakta ner" överföringen som tillhandahÄlls av kommunikationskanalen nÀr RTT ökar. För att öka effektiviteten och bÀttre utnyttja bandbredden i kommunikationskanalen anvÀnds pipelining.

AnvÀndning av pipelining leder till:
- ökat intervall för paketordningsnummer, eftersom alla skickade paket (utom Äterlevererade) mÄste kunna identifieras entydigt;
- behovet av att öka buffrar pÄ sÀndande och mottagande sida.
Intervall för paketordningsnummer och krav pÄ bufferstorlekar beror pÄ de ÄtgÀrder som protokollet vidtar som svar pÄ förvrÀngning, pakettapp och paketfördröjning. Vid pipelining finns det tvÄ metoder för felkorrigering:
- ÄtergÄng av N paket tillbaka;
- urval av upprepning.
Ă tervĂ€ndande av N paket tillbaka â glidande fönsterprotokoll

AvsÀndaren mÄste stödja tre typer av hÀndelser:
- anrop till ett protokoll av högre nivÄ. NÀr funktionen för att skicka data anropas "uppifrÄn", kontrollerar den sÀndande sidan först hur mycket utrymme som finns i fönstret (det vill sÀga om N meddelanden har skickats och vÀntar pÄ bekrÀftelser). Om fönstret inte Àr fullt, bildas ett nytt paket och sÀnds, och variablerna uppdateras. Annars returnerar den sÀndande sidan datan till den högre nivÄn, vilket Àr en tyst indikation pÄ att fönstret Àr fullt. Vanligtvis gör den högre nivÄn ett nytt försök att skicka data efter en tid. I en verklig applikation skulle avsÀndaren sannolikt antingen buffra data (istÀllet för att direkt skicka dem) eller ha en synkroniseringsmekanism (till exempel en semafor eller flagga) som tillÄter den högre nivÄn att anropa funktionen för att skicka data endast nÀr fönstret inte Àr fullt.
- mottagande av bekrÀftelse. I protokollet utfÀrdas en gemensam bekrÀftelse för paketet med nummer N, som anger att alla paket med nummers som föregÄr N har tagits emot framgÄngsrikt.
- timeout. För att faststÀlla förluster och fördröjningar av paket och bekrÀftelser anvÀnder protokollet en timer. Om timeouten intrÀffar skickar den sÀndande sidan om alla skickade, obekrÀftade paket.
selektivt ÄterutsÀndande
NÀr fönstrets storlek och produkten av bandbredd och spridningsfördröjning Àr stora, kan det finnas mÄnga paket i rörledningen. I ett sÄdant fall kan felet hos ett enskilt paket orsaka ÄterutsÀndning av mÄnga paket, varav de flesta inte behövdes.
Exempel
BĂ€sta metoder samlas i praktisk tillĂ€mpning . Och om nĂ„gon vet hur man gör det bĂ€ttre â .
Servern
package main
import (
"bufio"
"fmt"
"log"
"net"
"strings"
)
func main() {
// skapa en socket med port
ln, err := net.Listen("tcp", ":8081")
if err != nil {
log.Fatalln(err)
}
// vÀnta pÄ anrop
conn, _ := ln.Accept()
for {
// lÀsa data
msg, err := bufio.NewReader(conn).ReadString('n')
if err != nil {
log.Fatalln(err)
}
// skriva meddelande till stdout
fmt.Print("Meddelande mottaget:", string(msg))
// göra meddelandet till versaler
newMsg := strings.ToUpper(msg)
// skicka data
conn.Write([]byte(newMsg + "n"))
}
}Klient
paket huvud
import (
"bufio"
"fmt"
"log"
"net"
"os"
)
func huvud() {
// etablera anslutning
conn, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatalln(err)
}
for {
// lÀsa data frÄn stdin
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text att skicka: ")
// rad för rad
text, err := reader.ReadString('n')
if err != nil {
log.Fatalln(err)
}
// skicka
fmt.Fprintf(conn, text+"n")
// ta emot
msg, err := bufio.NewReader(conn).ReadString('n')
if err != nil {
log.Fatalln(err)
}
// skriv ut det mottagna svaret
fmt.Print("Meddelande frÄn server: " + msg)
}
}Utdata
Mekanismer som sÀkerstÀller pÄlitlig datatransmission och dess anvÀndning
Mekanismen
TillÀmpning, kommentar
Kontrollsumma
AnvÀnds för att upptÀcka bitfel i det överförda paketet
Timer
NedrÀkning av tidsintervallet och indikation pÄ dess utgÄng. Detta innebÀr att paketet eller dess bekrÀftelse sannolikt har gÄtt förlorad under överföringen. Om paketet levereras med fördröjning, men inte gÄr förlorat (för tidig tidsutgÄng), eller om bekrÀftelsen gÄr förlorad, resulterar en omöverföring i en duplicering av paketet pÄ mottagarens sida.
Sekvensnummer
AnvÀnds för sekventiell numrering av datapaket som överförs frÄn avsÀndare till mottagare. HÄl i sekvensnumren pÄ de mottagna paketen gör att mottagaren kan upptÀcka paketförlust. Duplicerade sekvensnummer av paket indikerar att paketen dupliceras.
BekrÀftelse
Genereras av mottagarsidan och anger till avsÀndarsidan att det aktuella paketet eller paketgrupp har mottagits framgÄngsrikt. BekrÀftelsen innehÄller vanligtvis sekvensnummer för de framgÄngsrikt mottagna paketen. Beroende pÄ protokollet sÀrskiljs individuella och grupperade bekrÀftelser.
Negativ bekrÀftelse
AnvÀnds av mottagaren för att meddela avsÀndaren att paketet har mottagits felaktigt. Den negativa bekrÀftelsen inkluderar vanligtvis sekvensnumret för det paket som inte har mottagits korrekt.
Fönster, pipelining
BegrÀnsar intervallet av ordningsnummer som kan anvÀndas för att överföra paket. Gruppenöverföring och handskakning gör det möjligt att avsevÀrt öka protokollens bandbredd jÀmfört med lÀget avvaktan pÄ bekrÀftelser. Som vi kommer att se kan fönsterstorleken berÀknas baserat pÄ mottagarens mottagnings- och buffringskapacitet samt nÀtverksbelastningen.
Andra exempel pÄ att anvÀnda Go för nÀtverksarbete.
I .
KĂ€lla: habr.com
