Найдвартай өгөгдөл дамжуулах үндэс

Найдвартай өгөгдөл дамжуулах үндэс

Хэнд хайж байна Сүлжээ, протоколыг ойлгоход зориулагдсан.

Товчхондоо

Нийтлэлд найдвартай өгөгдөл дамжуулах үндсийг авч үзэж, жишээнүүдийг хэрэгжүүлсэн болно GoUDP болон TCP зэрэг орно. Үндэслэн цаг хугацаа, два, гурав болон "Компьютерийн сүлжээ. Дээрээс доош хандлага" номууд, эс бөгөөс бүгд зөвхөн Танненбаум, Олиферов хоёрыг л хэлэлцэж байна.

Тээврийн түвшний протокол

Өөр өөр хостууд дээр ажиллаж байгаа хэрэглээний процессуудын логик холболтыг хангана. Хэрэглээний үүднээс авч үзвэл логик холболт нь процессуудыг шууд холбодог суваг шиг харагддаг.

Найдвартай өгөгдөл дамжуулах үндэс

Тээврийн түвшний протоколууд Төгсгөлийн системүүдээр дэмжигддэг боловч сүлжээний чиглүүлэгчид дэмждэггүй (-аас бусад нь) DPI). Илгээгчийн тал дээр тээврийн давхарга нь илгээх програмын процессоос хүлээн авсан хэрэглээний түвшний өгөгдлийг сегмент гэж нэрлэгддэг тээврийн түвшний багц болгон хувиргадаг.

Найдвартай өгөгдөл дамжуулах үндэс

Үүнийг (шаардлагатай бол) програмын давхаргын мессежүүдийг хэсэг болгон хувааж, тэдгээрт тээвэрлэх давхаргын толгойг нэмэх замаар хийдэг.

Найдвартай өгөгдөл дамжуулах үндэс

Дараа нь тээврийн давхарга нь сегментийг илгээгчийн сүлжээний давхарга руу дамжуулж, сегментийг сүлжээний түвшний пакет (датаграм) -д багтааж илгээдэг. Хүлээн авах төгсгөлд сүлжээний давхарга нь датаграмаас тээврийн давхаргын сегментийг гаргаж аваад тээврийн давхарга руу дамжуулдаг. Дараа нь тээврийн давхарга нь хүлээн авсан сегментийг боловсруулдаг бөгөөд ингэснээр түүний өгөгдөл нь хүлээн авагч програмд ​​хүрдэг.

Найдвартай өгөгдөл дамжуулах үндэс

Найдвартай өгөгдөл дамжуулах зарчим

Бүрэн аюулгүй сувгаар найдвартай өгөгдөл дамжуулах

Хамгийн энгийн тохиолдол. Илгээгч тал дээд давхаргаас өгөгдлийг хүлээн авч, түүнийг агуулсан пакет үүсгэн суваг руу илгээдэг.

Сервер

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)
    }
}

Болзошгүй алдаатай сувгаар найдвартай өгөгдөл дамжуулах

Дараагийн алхам бол бүх дамжуулагдсан пакетуудыг илгээсэн дарааллаар нь хүлээн авдаг гэж үзэх боловч суваг нь заримдаа гажуудалтай өгөгдлийг дамжуулдаг тул тэдгээрийн доторх битүүд гэмтсэн байж магадгүй юм.

Найдвартай өгөгдөл дамжуулах үндэс

Энэ тохиолдолд дараахь механизмуудыг ашигладаг.

  • алдаа илрүүлэх;
  • санал хүсэлт;
  • дахин дамжуулах.

Олон удаа давтан дамжуулах ижил төстэй механизмтай найдвартай өгөгдөл дамжуулах протоколуудыг Automatic Repeat ReQuest (ARQ) протокол гэж нэрлэдэг.
Нэмж дурдахад, хүлээн авагч тал сүүлийн багцын шилжүүлгийн үр дүнгийн талаар ямар ч мэдээлэл авахгүй байх үед төлбөрийн баримтад алдаа гарах магадлалыг анхаарч үзэх нь зүйтэй.
Энэ асуудлын шийдэл нь TCP-д бас хэрэглэгддэг бөгөөд багцын дарааллын дугаарыг агуулсан өгөгдлийн багцад шинэ талбар нэмэх явдал юм.

Найдвартай өгөгдөл дамжуулах үндэс

Пакетийн гажуудал, алдагдалд өртөж болзошгүй найдваргүй сувгаар найдвартай өгөгдөл дамжуулах

Харамсалтай нь гажуудалтай зэрэгцээд сүлжээнд пакет алдагдах тохиолдол гардаг.
Мөн энэ асуудлыг шийдэхийн тулд механизм шаардлагатай:

  • пакет алдагдсан баримтыг тодорхойлох;
  • алдагдсан пакетуудыг хүлээн авагч талд дахин хүргэх.

Нэмж дурдахад, багцыг алдахаас гадна баримтаа алдах, эсвэл юу ч алдагдаагүй бол хүргэх хугацааг ихээхэн хойшлуулах боломжийг бүрдүүлэх шаардлагатай. Бүх тохиолдолд ижил зүйл хийгддэг: пакетыг дахин дамжуулдаг. Цагийг хянахын тулд энэ механизм нь цаг тоолох таймерыг ашигладаг бөгөөд энэ нь хүлээлгийн интервалын төгсгөлийг тодорхойлох боломжийг олгодог. Тиймээс багцад цэвэр TCPKeepAlive-г анхдагчаар 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-ээс өмнөх дарааллын дугаартай бүх пакетуудыг амжилттай хүлээн авсныг харуулсан ерөнхий мэдэгдэл гаргасан.
  • хүлээх хугацаа дууссан. Багц, хүлээн авалтын алдагдал, саатлын баримтыг тодорхойлохын тулд протокол нь таймерыг ашигладаг. Хэрэв завсарлагааны хугацаа дуусвал илгээгч тал хүлээн зөвшөөрөөгүй бүх илгээсэн пакетуудыг дахин илгээнэ.

Сонгомол давталт

Цонхны хэмжээ болон дамжуулах чадвар-тархалтын саатлын бүтээгдэхүүн их байвал олон тооны пакетууд дамжуулах хоолойд байж болно. Ийм тохиолдолд нэг пакетийн алдаа нь олон тооны пакетуудыг дахин дамжуулахад хүргэж болох бөгөөд ихэнх нь шаардлагагүй байсан.

Жишээ нь:

Шилдэг, шилдэг онолын практикт хэрэгжүүлэх арга барилыг цуглуулдаг TCP. Хэрэв хэн нэгэн хамгийн сайн мэддэг бол - тавтай морилно уу.

Сервер

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)
    }
}

дүгнэлт

Мэдээлэл дамжуулах, ашиглах найдвартай байдлыг хангах механизм

Механизм
Өргөдөл, сэтгэгдэл

Шалгах нийлбэр
Дамжуулсан пакет дахь битийн алдааг илрүүлэхэд ашигладаг

Таймер
Хугацаа дуусах хугацааг тоолж, хугацаа нь дууссаныг заана. Сүүлийнх нь дамжуулах явцад пакет эсвэл түүний хүлээн авсан баримтыг алдах магадлал өндөр байна гэсэн үг юм. Хэрэв багц сааталтай хүргэгдсэн боловч алдагдаагүй (хугацаа хэтэрсэн хугацааны хугацаа хэтэрсэн) эсвэл баримт алдагдсан бол дахин дамжуулалт нь хүлээн авагч талд давхардсан багцад хүргэдэг.

Серийн дугаар
Илгээгчээс хүлээн авагч руу дамжих өгөгдлийн багцыг дараалан дугаарлахад ашигладаг. Хүлээн авсан пакетуудын дарааллын дугаарын зөрүү нь хүлээн авагчид пакет алдагдлыг илрүүлэх боломжийг олгодог. Ижил багцын дарааллын дугаарууд нь пакетууд бие биенийхээ давхардсан гэсэн үг юм

Баталгаажуулалт
Хүлээн авагч тал үүсгэсэн бөгөөд илгээгч талдаа харгалзах багц буюу багц багцыг амжилттай хүлээн авсныг илтгэнэ. Ихэвчлэн хүлээн авалт нь амжилттай хүлээн авсан пакетуудын дарааллын дугаарыг агуулдаг. Протоколоос хамааран хувь хүний ​​болон бүлгийн баталгаажуулалтыг ялгадаг

Сөрөг баталгаа
Хүлээн авагч нь илгээгчид пакетийг буруу хүлээн авсан тухай мэдэгдэхэд ашигладаг. Сөрөг хүлээн зөвшөөрөлт нь ихэвчлэн буруу хүлээн аваагүй багцын дарааллын дугаарыг агуулдаг

Цонх, конвейер
Пакет дамжуулахад ашиглаж болох дарааллын дугаарын хүрээг хязгаарлах. Олон дамжуулалт болон гар барих нь хүлээн зөвшөөрлийг хүлээхтэй харьцуулахад протоколын нэвтрүүлэх чадварыг мэдэгдэхүйц нэмэгдүүлэх боломжтой. Бидний харж байгаагаар цонхны хэмжээг хүлээн авагчийн хүлээн авах, буферлэх чадвар, сүлжээний ачааллын түвшинд үндэслэн тооцоолж болно.

Сүлжээнд Go-г ашиглах бусад жишээнүүд

В агуулахууд.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх