edənlərə
Qısaca
Məqalədə etibarlı məlumat ötürülməsinin əsasları müzakirə olunur, nümunələr tətbiq olunur
Nəqliyyat qatının protokolu
Müxtəlif hostlarda işləyən tətbiq prosesləri arasında məntiqi əlaqəni təmin edir. Tətbiq baxımından məntiqi əlaqə prosesləri birbaşa birləşdirən kanal kimi görünür.
Bu, tətbiq səviyyəsinin mesajlarını fraqmentlərə bölmək (lazım olduqda) və onların hər birinə nəqliyyat qatının başlığını əlavə etməklə həyata keçirilir.
Daha sonra nəqliyyat təbəqəsi seqmenti göndərənin şəbəkə səviyyəsinə ötürür, burada seqment şəbəkə qatı paketinə (dataqram) daxil edilir və göndərilir. Qəbul edən tərəfdə şəbəkə səviyyəsi dataqramdan nəqliyyat təbəqəsi seqmentini çıxarır və onu nəqliyyat qatına ötürür. Sonra, nəqliyyat təbəqəsi qəbul edilmiş seqmenti emal edir ki, onun məlumatları qəbul edən proqram üçün əlçatan olsun.
Etibarlı məlumat ötürülməsinin prinsipləri
Tamamilə təhlükəsiz kanal üzərindən etibarlı məlumat ötürülməsi
Ən sadə hal. Göndərən tərəf sadəcə olaraq yuxarı təbəqədən məlumatları qəbul edir, ondan ibarət paket yaradır və kanala göndərir.
Server
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 + надежный канал
}
}
Müştəri
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)
}
}
Mümkün səhvlərlə bir kanal üzərindən etibarlı məlumat ötürülməsi
Növbəti addım, bütün ötürülən paketlərin göndərildiyi ardıcıllıqla qəbul edildiyini güman etməkdir, lakin kanalın bəzən məlumatları təhriflərlə ötürməsi səbəbindən onlarda olan bitlər pozula bilər.
Bu vəziyyətdə aşağıdakı mexanizmlərdən istifadə olunur:
- səhv aşkarlanması;
- rəy;
- təkrar ötürülmə.
Bir neçə dəfə təkrar ötürmə üçün oxşar mexanizmlərə malik olan etibarlı məlumat ötürmə protokolları Avtomatik Təkrar Sorğu (ARQ) protokolları adlanır.
Əlavə olaraq, qəbul edən tərəf son paketin ötürülməsinin nəticələri haqqında heç bir məlumat almadıqda qəbzlərdə səhvlərin olma ehtimalını nəzərə almağa dəyər.
TCP-də də istifadə edilən bu problemin həlli paketin ardıcıl nömrəsini ehtiva edən məlumat paketinə yeni sahə əlavə etməkdir.
Paket təhrifinə və itkisinə məruz qalan etibarsız bir kanal üzərindən etibarlı məlumat ötürülməsi
Təhriflə yanaşı, təəssüf ki, şəbəkədə paket itkisi də var.
Və bu problemi həll etmək üçün mexanizmlər tələb olunur:
- paketin itirilməsi faktının müəyyən edilməsi;
- itirilmiş paketlərin qəbul edən tərəfə yenidən çatdırılması.
Bundan əlavə, bağlamanın itirilməsi ilə yanaşı, qəbzin itirilməsi və ya heç bir şey itirilməyibsə, əhəmiyyətli bir gecikmə ilə çatdırılması ehtimalını təmin etmək lazımdır. Bütün hallarda eyni şey edilir: paket yenidən ötürülür. Vaxta nəzarət etmək üçün bu mexanizm gözləmə intervalının sonunu müəyyən etməyə imkan verən geri sayım taymerindən istifadə edir. Beləliklə, paketdə
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)
Göndərən tərəf hər dəfə paket ötürüldükdə (həm birinci, həm də ikinci dəfə) taymeri işə salmalı, taymerdən gələn fasilələri idarə etməli və onu dayandırmalıdır.
Beləliklə, biz etibarlı məlumat ötürmə protokollarının əsas anlayışları ilə tanış olduq:
- yoxlama məbləğləri;
- bağlamaların ardıcıl nömrələri;
- taymerlər;
- müsbət və mənfi qəbzlər.
Ancaq bu, hamısı deyil!
Boru kəməri ilə etibarlı məlumat ötürmə protokolu
Artıq nəzərdən keçirdiyimiz variantda etibarlı çatdırılma protokolu çox səmərəsizdir. RTT artdıqca rabitə kanalı tərəfindən təmin edilən ötürülməni "yavaşlamağa" başlayır. Onun səmərəliliyini artırmaq və rabitə kanalının tutumundan daha yaxşı istifadə etmək üçün boru kəmərindən istifadə olunur.
Boru kəmərinin istifadəsi aşağıdakılara səbəb olur:
- ardıcıllıq nömrələrinin diapazonunun artırılması, çünki bütün göndərilən paketlər (yenidən ötürülmələr istisna olmaqla) unikal şəkildə müəyyən edilməlidir;
- ötürən və qəbul edən tərəflərdə tamponların artırılması ehtiyacı.
Ardıcıllıq nömrəsi diapazonu və bufer ölçüsü tələbləri protokolun paketin pozulması, itkisi və gecikməsinə cavab olaraq gördüyü tədbirlərdən asılıdır. Boru kəməri vəziyyətində səhvləri düzəltmək üçün iki üsul var:
- N paketi geri qaytarın;
- seçmə təkrar.
N paketə qayıtmaq - sürüşmə pəncərə protokolu
Göndərən üç növ hadisəni dəstəkləməlidir:
- daha yüksək səviyyəli protokolla zəng edin. Məlumat göndərmə funksiyası "yuxarıdan" adlandırıldıqda, göndərən tərəf əvvəlcə pəncərənin doldurulma dərəcəsini yoxlayır (yəni qəbzlərin alınmasını gözləyən N göndərilmiş mesajın olması). Pəncərə boşdursa, yeni paket yaradılır və ötürülür və dəyişən dəyərlər yenilənir. Əks halda, göndərən tərəf məlumatları yuxarı təbəqəyə qaytarır və bu, pəncərənin dolu olduğunun gizli göstəricisidir. Tipik olaraq, yuxarı təbəqə bir müddət sonra məlumatları yenidən ötürməyə çalışacaq. Həqiqi tətbiqdə, göndərici, ehtimal ki, məlumatları ya tamponlayacaq (dərhal göndərmək əvəzinə) və ya yuxarı təbəqəyə göndərmə funksiyasını yalnız pəncərə boş olduqda çağırmağa imkan verən sinxronizasiya mexanizminə (məsələn, semafor və ya bayraq) malik olacaq. .
- təsdiqin alınması. Protokolda sıra nömrəsi N olan paket üçün N-dən əvvəl ardıcıllıq nömrələri olan bütün paketlərin uğurla qəbul edildiyini bildirən ümumi bildiriş verilir.
- gözləmə intervalı başa çatıb. Paketlərin və qəbzlərin itkiləri və gecikmələri faktlarını müəyyən etmək üçün protokol taymerdən istifadə edir. Taymout intervalı başa çatarsa, göndərən tərəf bütün göndərilən qəbul edilməmiş paketləri yenidən göndərir.
Seçmə təkrar
Pəncərə ölçüsü və ötürmə qabiliyyətinin yayılması gecikmə məhsulu böyük olduqda, boru kəmərində çoxlu sayda paket ola bilər. Belə olan halda, tək paket xətası çoxlu sayda paketin təkrar ötürülməsinə səbəb ola bilər, onların əksəriyyəti tələb olunmur.
Misal
Üst
Server
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"))
}
}
Müştəri
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)
}
}
Buraxılış
Etibarlı məlumat ötürülməsini və istifadəsini təmin edən mexanizmlər
Mexanizm
Ərizə, şərh
Yoxlama məbləği
Köçürülən paketdə bit xətalarını aşkar etmək üçün istifadə olunur
Timer
Taymout intervalını geri sayır və onun nə vaxt bitdiyini göstərir. Sonuncu o deməkdir ki, ötürmə zamanı paketin və ya onun qəbzinin itirilməsi ehtimalı yüksəkdir. Paket gecikmə ilə çatdırılırsa, lakin itmirsə (taym-aut intervalının vaxtından əvvəl başa çatması) və ya qəbz itirilirsə, təkrar ötürmə qəbul edən tərəfdə dublikat paketə səbəb olur.
Seriya nömrəsi
Göndərəndən alıcıya ötürülən məlumat paketlərinin ardıcıl nömrələnməsi üçün istifadə olunur. Qəbul edilən paketlərin ardıcıl nömrələrindəki boşluqlar alıcıya paket itkisini aşkar etməyə imkan verir. Eyni paket ardıcıllıq nömrələri paketlərin bir-birinin dublikatları olduğunu bildirir
Təsdiq
Qəbul edən tərəf tərəfindən yaradılır və göndərən tərəfə müvafiq paketin və ya paketlər qrupunun uğurla qəbul edildiyini göstərir. Bir qayda olaraq, təsdiq uğurla qəbul edilmiş paketlərin ardıcıl nömrələrini ehtiva edir. Protokoldan asılı olaraq fərdi və qrup təsdiqləmələri fərqləndirilir
Mənfi təsdiq
Alıcı tərəfindən paketin səhv qəbul edildiyi barədə göndərənə məlumat vermək üçün istifadə olunur. Mənfi təsdiq adətən düzgün qəbul edilməmiş paketin sıra nömrəsini ehtiva edir
Pəncərə, konveyerləşdirmə
Paketləri ötürmək üçün istifadə edilə bilən ardıcıl nömrələr diapazonunu məhdudlaşdırın. Multicast və handshake protokolun ötürmə qabiliyyətini təşəkkürləri gözləməkdən əhəmiyyətli dərəcədə artıra bilər. Görəcəyimiz kimi, pəncərənin ölçüsü qəbuledici tərəfin qəbulu və tamponlama imkanlarına, həmçinin şəbəkənin yüklənmə səviyyəsinə əsasən hesablana bilər.
Şəbəkə üçün Go istifadəsinin daha çox nümunələri
В
Mənbə: www.habr.com