
Նրանց, ովքեր Նվիրված է ցանցերի և արձանագրությունների ըմբռնմանը։
Համառոտ
Հոդվածում քննարկվում են հուսալի տվյալների փոխանցման հիմունքները և կիրառվում են օրինակներ , ներառյալ UDP և TCP: Հիմնված է , , և «Համակարգչային ցանցեր։ Վերևից ներքև մոտեցում» գիրքը, հակառակ դեպքում բոլորը քննարկում են միայն Տանենբաումին և Օլիֆերովին։
Տրանսպորտային շերտի արձանագրություն
Ապահովում է տրամաբանական կապ տարբեր հոսթերի վրա աշխատող ծրագրային գործընթացների միջև։ Լոգիկական կապը ծրագրային ապահովման համար ներկայացվում է որպես գործընթացները ուղղակիորեն միացնող ալիք։

աջակցվում է վերջնային համակարգերի կողմից, բայց ոչ ցանցային ռաութերների կողմից (բացառությամբ՝ )։ Ուղարկողի կողմից տրանսպորտային շերտը փոխանցող կիրառական գործընթացից ստացված կիրառական շերտի տվյալները փոխակերպում է տրանսպորտային շերտի փաթեթների, որոնք կոչվում են հատվածներ։

Սա արվում է՝ (անհրաժեշտության դեպքում) կիրառական շերտի հաղորդագրությունները բաժանելով ֆրագմենտների և դրանցից յուրաքանչյուրին ավելացնելով տրանսպորտային շերտի վերնագիր։

Այնուհետև տրանսպորտային շերտը հատվածը փոխանցում է ուղարկողի ցանցային շերտին, որտեղ այն փաթեթավորվում է ցանցային շերտի փաթեթի (դատագրամի) մեջ և ուղարկվում: Ստացող կողմում ցանցային շերտը տրանսպորտային շերտի հատվածը արդյունահանում է դատագրամից և փոխանցում այն տրանսպորտային շերտին: Այնուհետև տրանսպորտային շերտը մշակում է ստացված հատվածը, որպեսզի դրա տվյալները հասանելի դառնան ստացող ծրագրին:

Անվտանգ տվյալների փոխանցման սկզբունքները
Հուսալի տվյալների փոխանցում լիովին անվտանգ ալիքով
Ամենապարզ դեպքը. ուղարկող կողմը պարզապես ստանում է տվյալներ վերին շերտից, ստեղծում է դրանք պարունակող փաթեթ և ուղարկում է այն ալիքին։
Սերվեր
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 + надежный канал
}
}Հաճախորդը
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)
}
}Հուսալի տվյալների փոխանցում ալիքով հնարավոր սխալներով
Հաջորդ քայլը ենթադրելն է, որ բոլոր փոխանցված փաթեթները ստացվում են ուղարկման հերթականությամբ, սակայն դրանցում առկա բիթերը կարող են վնասված լինել այն պատճառով, որ ալիքը երբեմն տվյալներ է փոխանցում աղավաղումներով։

Այս դեպքում կիրառվում են հետևյալ մեխանիզմները.
- սխալի հայտնաբերում;
- հետադարձ կապ;
- վերահեռարձակում։
Հուսալի տվյալների փոխանցման արձանագրությունները, որոնք ունեն փոխանցման բազմակի կրկնության նման մեխանիզմներ, կոչվում են ավտոմատ կրկնության հարցման (ARQ) արձանագրություններ։
Բացի այդ, արժե հաշվի առնել անդորրագրերում սխալների հնարավորությունը, երբ ստացող կողմը որևէ տեղեկատվություն չի ստանում վերջին փաթեթի փոխանցման արդյունքների մասին:
Այս խնդրի լուծումը, որն օգտագործվում է TCP-ում, ի թիվս այլ բաների, տվյալների փաթեթին նոր դաշտ ավելացնելն է, որը պարունակում է փաթեթի հաջորդական համարը։

Հուսալի տվյալների փոխանցում անվստահելի ալիքով, որը թույլ է տալիս փաթեթների աղավաղում և կորուստ
Աղավաղումների հետ մեկտեղ, ցավոք, ցանցում կա փաթեթների կորուստ։
Եվ այս խնդիրը լուծելու համար անհրաժեշտ են հետևյալ մեխանիզմները.
- փաթեթի կորստի փաստի որոշում;
- կորած փաթեթների վերահասցեագրումը ստացող կողմին։
Բացի այդ, փաթեթի կորստից բացի, անհրաժեշտ է նախատեսել ստացականի կորստի կամ, եթե ոչինչ չի կորչում, դրա զգալի ուշացմամբ առաքման հնարավորությունը: Բոլոր դեպքերում նույն բանն է արվում՝ փաթեթի վերահաղորդում: Ժամանակը կառավարելու համար այս մեխանիզմն օգտագործում է հետհաշվարկի ժամանակաչափ, որը թույլ է տալիս որոշել սպասման ժամանակահատվածի ավարտը: Այսպիսով, փաթեթում TCKeepAlive-ը լռելյայնորեն սահմանված է 15 վայրկյանի վրա։
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)Փոխանցող կողմը պետք է միացնի ժամանակաչափը ամեն անգամ, երբ փաթեթը փոխանցվում է (և՛ առաջին, և՛ երկրորդ անգամ), կարգավորի ժամանակաչափի ընդհատումները և կանգնեցնի այն։
Այսպիսով, մենք ծանոթացանք հուսալի տվյալների փոխանցման արձանագրությունների հիմնական հասկացություններին.
- ստուգիչ գումարներ;
- փաթեթների սերիական համարները;
- ժամանակաչափեր;
- դրական և բացասական ստացականներ։
Բայց դա դեռ ամենը չէ։
Հուսալի տվյալների փոխանցման արձանագրություն՝ խողովակաշարով
Մեր արդեն դիտարկած տարբերակում հուսալի առաքման արձանագրությունը շատ անարդյունավետ է: Այն սկսում է «դանդաղեցնել» կապի ալիքի կողմից ապահովվող փոխանցումը, երբ RTT-ն աճում է: Դրա արդյունավետությունը բարձրացնելու և կապի ալիքի թողունակությունն ավելի լավ օգտագործելու համար օգտագործվում է խողովակաշարային տեխնոլոգիա:

Խողովակաշարերի օգտագործումը հանգեցնում է հետևյալի.
- հաջորդական համարների միջակայքի ավելացում, քանի որ բոլոր ուղարկված փաթեթները (բացառությամբ վերահաղորդումների) պետք է լինեն միանշանակ նույնականացվող։
- փոխանցող և ընդունող կողմերի բուֆերները մեծացնելու անհրաժեշտությունը։
Հաջորդական համարների միջակայքը և բուֆերի չափերի պահանջները կախված են արձանագրության կողմից փաթեթների վնասման, կորստի և ուշացման դեպքում ձեռնարկված գործողություններից: Խողովակաշարային համակարգի դեպքում կան սխալների ուղղման երկու մեթոդ.
- վերադարձնել N փաթեթները;
- ընտրողական կրկնություն։
Հետընթաց N փաթեթներ - սահող պատուհանի արձանագրություն

Ուղարկողը պետք է աջակցի երեք տեսակի իրադարձությունների՝
- կանչը կատարվում է ավելի բարձր մակարդակի արձանագրությամբ: Երբ վերևից կանչվում է ուղարկման ֆունկցիա, ուղարկողը նախ ստուգում է, թե արդյոք պատուհանը լիքն է (այսինքն՝ արդյոք կան N ուղարկված հաղորդագրություններ, որոնք սպասում են հաստատման): Եթե պատուհանը լիքն չէ, ձևավորվում և փոխանցվում է նոր փաթեթ, և փոփոխականների արժեքները թարմացվում են: Հակառակ դեպքում ուղարկողը տվյալները վերադարձնում է վերին շերտ, ինչը անուղղակի ցուցում է, որ պատուհանը լիքն է: Սովորաբար, վերին շերտը որոշ ժամանակ անց կրկին կփորձի փոխանցումը: Իրական կիրառման մեջ ուղարկողը, ամենայն հավանականությամբ, կամ կբուֆերացնի տվյալները (անմիջապես ուղարկելու փոխարեն), կամ կունենա համաժամացման մեխանիզմ (օրինակ՝ սեմաֆոր կամ դրոշ), որը թույլ կտա վերին շերտին կանչել ուղարկման ֆունկցիան միայն այն դեպքում, երբ պատուհանը լիքն չէ:
- Հաստատման ստացում։ Արձանագրության մեջ N հաջորդական համարով փաթեթի համար տրվում է ընդհանուր հաստատում, որը ցույց է տալիս, որ N-ից առաջ հաջորդական համարներով բոլոր փաթեթները հաջողությամբ ստացվել են։
- Ժամանակի սպառում։ Արձանագրությունն օգտագործում է ժամանակաչափ՝ փաթեթների և հաստատման կորուստը, ինչպես նաև ուշացումները հայտնաբերելու համար։ Եթե ժամանակի սպառումը լրանա, փոխանցող կողմը վերուղարկում է ուղարկված բոլոր չհաստատված փաթեթները։
Ընտրողական կրկնություն
Երբ պատուհանի չափը և թողունակության ուշացման արտադրյալը մեծ են, խողովակաշարում կարող է լինել մեծ թվով փաթեթներ։ Այս դեպքում, մեկ փաթեթի սխալը կարող է հանգեցնել մեծ թվով փաթեթների վերահաղորդման, որոնց մեծ մասը անհրաժեշտ չէր։
Օրինակ
Վերեւ պրակտիկաները հավաքվում են գործնական իրականացման մեջ Եվ եթե ինչ-որ մեկը ավելի լավ գիտի՝ .
Սերվեր
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"))
}
}Հաճախորդը
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)
}
}Արտադրողականություն
Մեխանիզմներ, որոնք ապահովում են տվյալների հուսալի փոխանցում և օգտագործում
մեխանիզմ
Դիմում, մեկնաբանություն
Ստուգիչ գումար
Օգտագործվում է փոխանցված փաթեթում բիթային սխալները հայտնաբերելու համար։
Ժմչփ
Ժամանակի ավարտի ժամանակահատվածի հաշվարկը և դրա ժամկետի նշումը։ Վերջինս նշանակում է, որ մեծ հավանականությամբ փաթեթը կամ դրա ստացականը կորել է փոխանցման ընթացքում։ Եթե փաթեթը առաքվում է ուշացումով, բայց չի կորում (ժամանակի ավարտի ժամանակահատվածի վաղաժամ ավարտ), կամ ստացականը կորչում է, վերահաղորդումը հանգեցնում է փաթեթի կրկնօրինակման ընդունող կողմում։
Սերիական համար
Օգտագործվում է ուղարկողից ստացողին փոխանցված տվյալների փաթեթների հաջորդական համարակալման համար։ Ստացված փաթեթների հաջորդական համարների բացթողումները թույլ են տալիս ստացողին հայտնաբերել փաթեթների կորուստը։ Փաթեթների նույնական հաջորդական համարները նշանակում են, որ փաթեթները միմյանց կրկնօրինակներ են։
Հաստատում
Ստեղծվում է ընդունող կողմի կողմից և տեղեկացնում է փոխանցող կողմին, որ համապատասխան փաթեթը կամ փաթեթների խումբը հաջողությամբ ստացվել է: Սովորաբար, հաստատումը պարունակում է հաջողությամբ ստացված փաթեթների հաջորդական համարները: Կախված արձանագրությունից, տարբերակվում են անհատական և խմբային հաստատումները:
Բացասական հաստատում
Օգտագործվում է ստացողի կողմից՝ ուղարկողին տեղեկացնելու համար, որ փաթեթը ճիշտ չի ստացվել: Բացասական հաստատումը սովորաբար ներառում է սխալ ստացված փաթեթի հաջորդական համարը:
Պատուհան, խողովակաշար
Սահմանափակեք փաթեթներ փոխանցելու համար օգտագործվող հաջորդական համարների միջակայքը: Բազմահեռարձակման և ձեռքսեղմման արձանագրությունները կարող են զգալիորեն մեծացնել թողունակությունը՝ համեմատած ACK-սպասող ռեժիմի հետ: Ինչպես կտեսնենք, պատուհանի չափը կարող է հաշվարկվել ընդունող կողմի ընդունման և բուֆերացման հնարավորությունների, ինչպես նաև ցանցի ծանրաբեռնվածության հիման վրա:
Go Networking-ի ավելի շատ օրինակներ
В .
Source: www.habr.com
