
Atij që të kuptojnë rrjetet dhe protokollet, i dedikohet.
Në përmbledhje
Në këtë artikull shqyrtohen të gjithë bazat e transmetimit të sigurt të të dhënave, duke ilustruar shembuj në , përfshirë UDP dhe TCP. Në frymëzuar nga , , dhe libri "Rrjetet kompjuterike. Qasja nga poshtë", pasi të gjithë flasin vetëm për Tanenbaum dhe Olifer.
Protokolli i nivelit transportues
garanton një lidhje logjike midis proceseve aplikative që po ekzekutohen në hoste të ndryshme. Lidhja logjike nga perspektiva e aplikacioneve duket si një kanal që lidh drejtpërdrejt proceset.

mbështeten nga sistemet e fundit, por jo nga ruterët rrjetit (përveç - ). Në anën e dërguesit, niveli transportues kthen të dhënat e nivelit aplikativ që merr nga procesi aplikativ dërgues në paketa të nivelit transportues, të quajtura segmente.

Kjo realizohet duke copëtuar (në rast nevoje) mesazhet e nivelit aplikativ në fragmente dhe duke shtuar një kokëz të nivelit transportues në secilin prej tyre.

Pastaj, niveli transportues dërgon segmentin në nivelin rrjetit të dërguesit, ku segmenti inkapsulohet në një paketë të nivelit rrjetit (datagram) dhe dërgohet. Në anën e marrësit, niveli rrjetit nxjerr segmentin e nivelit transportues nga datagrami dhe e transmeton lart në nivelin transportues. Pastaj niveli transportues përpunon segmentin e marrë në mënyrë që të dhënat e tij të bëhen të disponueshme për aplikacionin marrës.

Parimet e transmetimit të sigurt të të dhënave
Transmetimi i sigurt i të dhënave përmes një kanali krejtësisht të besueshëm
Rasti më i thjeshtë. Anëtari dërgues thjesht merr të dhënat nga niveli i lartë, krijon paketën që i përmban ato dhe e dërgon në kanal.
Server
paketa kryesore
import (
"log"
"net"
)
funksioni kryesor() {
\/\/ Adresa IP e serverit dhe porta
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
nëse err != nil {
log.Fatal(err)
}
\/\/ krijo një socket me portin
serverConn, err := net.ListenUDP("udp", serverAddr)
nëse err != nil {
log.Fatal(err)
}
\/\/ mbyllja e vonuar e lidhjes
defer serverConn.Close()
\/\/ krijo një tampon për të dhënat
buf := make([]byte, 1024)
\/\/ presim lidhjen
për {
\/\/ lexojmë kërkesën
n, addr, err := serverConn.ReadFromUDP(buf)
\/\/ dĂ«rgojmĂ« tĂ« dhĂ«nat nĂ« nivelin E LARTĂ: nĂ« rastin tonĂ« stdout
println(string(buf[0:n]), " nga ", addr.IP.String())
nëse err != nil {
log.Fatal(err)
}
\/\/ nuk ka përgjigje, pasi ky është UDP + një kanal të besueshëm
}
}KÎ»ÎŻÎżÏ ent
paketa kryesore
import (
"fmt"
"log"
"net"
"time"
)
funksioni kryesor() {
\/\/ Adresa IP e serverit dhe porta
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:12000")
nëse err != nil {
log.Fatal(err)
}
\/\/ adresa lokale IP dhe porta
localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
nëse err != nil {
log.Fatal(err)
}
\/\/ vendos lidhjen
conn, err := net.DialUDP("udp", localAddr, serverAddr)
nëse err != nil {
log.Fatal(err)
}
\/\/ mbyllja e vonuar e lidhjes
defer conn.Close()
për {
\/\/ marrja e tĂ« dhĂ«nave nga niveli I LARTĂ
fmt.Print("Shkruani një frazë > ")
var msg string
_, err := fmt.Scanf("%s", &msg)
nëse err != nil {
log.Fatal(err)
}
\/\/ dërgohet një rrjedhë byte, jo një varg
buf := []byte(msg)
\/\/ shkrimi (dërgimi) në lidhje
_, err = conn.Write(buf)
nëse err != nil {
log.Fatal(err)
}
\/\/ 1 sekondë
time.Sleep(time.Second * 1)
}
}Transferi i besueshëm i të dhënave përmes një kanali me mundësi gabimesh
Hapi tjetër është të supozojmë se të gjitha paketat e dërguara janë marrë në rendin në të cilin janë dërguar, por bitet në to mund të jenë të dëmtuara, për shkak se kanali ndonjëherë dërgon të dhëna me deformime.

Në këtë rast, përdoren mekanizmat:
- zbulimi i gabimeve;
- feedback;
- rikthimi i dërgimit.
Protokollet e besueshëm të transferimit të të dhënave që kanë mekanizma të tillë për përsëritjen e dërgimit, quhen protokolle me kërkesë automatik të përsëritjes (Automatic Repeat reQuest, ARQ).
Për më tepër, është e nevojshme të parashikohet mundësia e gabimeve edhe në konfirmimet, kur pala që pranon nuk merr asnjë informacion mbi rezultatet e transferimit të paketës së fundit.
Zgjidhja e kësaj çështjeje, e përdorur gjithashtu në TCP, përbëhet nga shtimi në paketë të një fushe të re të dhënash që përmban numrin rresht të paketës.

Transferimi i sigurt i të dhënave përmes një kanali të pasigurt, që pranon deformime dhe humbjen e paketimeve.
Fatkeqësisht, gjatë deformimeve, rrjeti ka gjithashtu humbje paketi.
Dhe për të zgjidhur këtë problem nevojiten mekanizma:
- për të përcaktuar humbjen e paketimeve;
- për ri-dërgimin e paketimeve të humbura në anën e marrësit.
Për më tepër, përveç humbjes së paketës, duhet të parashikohet humbja e konfirmimit ose, nëse nuk ka asgjë të humbur, dërgimi i tij me një vonesë të konsiderueshme. Në të gjitha rastet kryhet e njëjta veprim: ri-dërgimi i paketës. Për të kontrolluar kohën në këtë mekanizëm përdoret një numërator i prishur, i cili lejon përcaktimin e përfundimit të intervalit të pritjes. Kështu, në paketë, parametri TCPKeepAlive është vendosur në 15 sekonda si parazgjedhje:
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)Anës transmetuese duhet të aktivizojë numëratorin çdo herë kur dërgon një paketë (si në të parën ashtu edhe në ri-dërgimin), të shqyrtojë ndërprerjet nga numëratori dhe ta ndalë atë.
Pra, ne u njohëm me konceptet kryesore të protokolleve të transmetimit të sigurt të të dhënave:
- kontrollin e shumave;
- numrat rendorë të paketimeve;
- numëratorët;
- konfirmimet pozitive dhe negative.
Por kjo nuk është e gjitha!
Protokolli i sigurimit të transmetimit të të dhënave me konvejering
Në atë variant që kemi shqyrtuar, protokolli i dorëzimit të sigurt është shumë i paefikas. Ai fillon "të ngadalësojë" transmetimin, duke e siguruar kanalin e komunikimit, me rritjen e RTT. Për të rritur efikasitetin e tij, përdoret konvejeringu për një shfrytëzim më të mirë të kapacitetit të kanalit të komunikimit.

Përdorimi i konvejeringut çon në:
- rritjen e gamës së numrave rendorë, pasi të gjithë paketat e dërguara (përveç ri-dërgesave) duhet të jenë të identifikueshme qartë;
- nevojën për rritjen e tamponëve në anën transmetuese dhe atë marrëse.
Gama e numrave rendorë dhe kërkesat për madhësitë e tamponëve varen nga veprimet që ndërmerr protokolli si përgjigje ndaj deformimeve, humbjeve dhe vonesave të paketimeve. Në rastin e konvejeringut ka dy metoda për korrigjimin e gabimeve:
- kthimi mbrapa për N paketa;
- ribashkërkoi selektive.
Kthimi mbrapa për N paketa - protokolli i dritares së gliding

Dërguesi duhet të mbështesë tre lloje ngjarjesh:
- згjedhja e protokolit më të lartë. Kur funksioni për dërgimin e të dhënave thirret "nga lart", pala që dërgon së pari kontrollon shkallën e përmbushjes së dritares (domethënë prania e N mesazheve të dërguara që presin pranimin e konfirmacioneve). Nëse dritarja rezulton e zbrazët, formohet një paketë e re dhe dërgohet, dhe vlerat e variablave përditësohen. Në të kundërt, pala që dërgon i kthen të dhënat nivelit të lartë, dhe kjo është një tregues i heshtur që dritarja është e mbushur. Zakonisht niveli më i lartë përpiqet përsëri të dërgojë të dhënat pas një kohe. Në një aplikacion real, dërguesi me shumë mundësi do të kishte ose bufferizuar të dhënat (në vend të dërgimit të menjëhershëm), ose do të kishte një mekanizëm sinkronizimi (p.sh., semafor ose flamur) që do t'i lejonte nivelit më të lartë të thërrasë funksionin e dërgimit të të dhënave vetëm kur dritarja të ishte e zbrazët.
- marrja e konfirmimit. Në protokollin për paketën me numrin e rendit N lëshohet një konfirmim i përgjithshëm që tregon se të gjitha paketat me numrat e rendit që e parashikojnë N janë pranuar me sukses.
- skadimi i intervalit të pritjes. Për të përcaktuar faktet e humbjeve dhe vonesave të paketimeve dhe konfirmacioneve protokolli përdor një timer. Nëse skadon intervali i pritjes, pala që dërgon dërgon përsëri të gjitha paketat e dërguara që nuk janë konfirmuar.
Ribërja selektive
Kur madhësia e dritares dhe produkti i kapacitetit të kalimit me vonesën e shpërndarjes janë të mëdha, në tub është e mundur të ndodhen shumë paketa. Në një rast të tillë, gabimi i një pakete të veçantë mund të shkaktojë përsëritjen e dërgimit të një numri të madh paketash, shumica e të cilave nuk ishin të nevojshme.
Shembulli
MĂ« tĂ« mirat praktikat janĂ« mbledhur nĂ« zbatimin praktik . Dhe nĂ«se dikush di ndonjĂ« gjĂ« mĂ« tĂ« mirĂ« â .
Server
package main
import (
"bufio"
"fmt"
"log"
"net"
"strings"
)
func main() {
// krijojmë një soket me port
ln, err := net.Listen("tcp", ":8081")
if err != nil {
log.Fatalln(err)
}
// pritja e thirrjes
conn, _ := ln.Accept()
for {
// leximi i të dhënave
msg, err := bufio.NewReader(conn).ReadString('n')
if err != nil {
log.Fatalln(err)
}
// dalja e mesazhit në stdout
fmt.Print("Mesazhi i Marrë:", string(msg))
// përkthimi i vargut në shkronja të mëdha
newMsg := strings.ToUpper(msg)
// dërgimi i të dhënave
conn.Write([]byte(newMsg + "n"))
}
}KÎ»ÎŻÎżÏ ent
paket kryesor
import (
"bufio"
"fmt"
"log"
"net"
"os"
)
func main() {
\/\/ vendosja e lidhjes
conn, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatalln(err)
}
for {
\/\/ leximi i të dhënave nga stdin
reader := bufio.NewReader(os.Stdin)
fmt.Print("Teksti për të dërguar: ")
\/\/ rresht pas rreshti
text, err := reader.ReadString('n')
if err != nil {
log.Fatalln(err)
}
\/\/ dërgimi
fmt.Fprintf(conn, text+"n")
\/\/ marrja
msg, err := bufio.NewReader(conn).ReadString('n')
if err != nil {
log.Fatalln(err)
}
\/\/ shfaqja e përgjigjes së marrë
fmt.Print("Mesazhi nga Serveri: " + msg)
}
}Përfundimi
Mekanizmat që sigurojnë transmetimin e besueshëm të të dhënave dhe përdorimin e tyre
Mekanizmi
Përdorimi, komentimi
Kontrolli i shumës
Përdoret për të zbuluar gabimet në bitet e paketës së dërguar
Nënpërmjet këndit
Numërimi i intervalit të pritjes dhe tregimi i përfundimit të tij. E fundit do të thotë se me një probabilitet të lartë paketa ose konfirmimi i saj janë humbur gjatë dërgimit. Në rast se paketa arrin me vonesë, por nuk humbet (skadimi i parakohshëm i intervalit të pritjes), ose ndodh humbja e konfirmimit, ripaketimi çon në dublikimin e paketës në anën e marrësit
Numri rendor
Përdoret për numërimin rendor të paketave të dhënash të dërguara nga dërguesi te marrësi. Ndërprerjet në numrat rendor të paketave të marra lejojnë marrësin të zbulojë humbjen e paketës. Numrat rendor të barabartë të paketave nënkuptojnë se paketat dublikojnë njëra-tjetrën
Konfirmimi
Krijohet nga ana e marrësit dhe i tregon dërguesit se paketa ose grupi i paketave përkatëse janë pranuar me sukses. Zakonisht konfirmimi përmban numrat rendor të paketave të pranuara me sukses. Në varësi të protokollit, dallohen konfirmime individuale dhe grupore
Konfirmimi negativ
Përdoret nga marrësi për t'i njoftuar dërguesit se paketa është marrë gabim. Konfirmimi negativ zakonisht përfshin numrin rendor të paketës që nuk është marrë siç duhet
Dritarja, konvejimi
Kufizojnë gamën e numrave ordinal që mund të përdoren për transfertën e paketave. Transfertat në grup dhe dorëzimi lejojnë të rritet ndjeshëm kapaciteti i protokolleve krahasuar me modalitetin e pritjes për konfirmime. Siç do ta shohim, madhësia e dritares mund të llogaritet mbi baza të mundësive të pranimit dhe buferizimit të palës marrëse, si dhe nivelit të ngarkesës së rrjetit.
Shembuj të tjerë të përdorimit të Go për punë me rrjetin.
NĂ« .
Burimi: habr.com
