Asas Pemindahan Data Boleh Dipercayai

Asas Pemindahan Data Boleh Dipercayai

Kepada mereka yang mencari Didedikasikan untuk memahami rangkaian dan protokol.

Secara ringkas

Artikel membincangkan asas penghantaran data yang boleh dipercayai, melaksanakan contoh pada Go, termasuk UDP dan TCP. Berdasarkan masa, два, 3 dan buku "Rangkaian Komputer. Pendekatan Atas Bawah", jika tidak, semua orang hanya membincangkan Tannenbaum dan Oliferov.

Protokol lapisan pengangkutan

Menyediakan sambungan logik antara proses aplikasi yang berjalan pada hos yang berbeza. Dari perspektif aplikasi, sambungan logik kelihatan seperti saluran yang menghubungkan proses secara langsung.

Asas Pemindahan Data Boleh Dipercayai

Protokol lapisan pengangkutan disokong oleh sistem akhir, tetapi bukan oleh penghala rangkaian (kecuali - DPI). Di bahagian penghantar, lapisan pengangkutan menukar data lapisan aplikasi yang diterima daripada proses aplikasi penghantaran ke dalam paket lapisan pengangkutan yang dipanggil segmen.

Asas Pemindahan Data Boleh Dipercayai

Ini dilakukan dengan membelah (jika perlu) mesej lapisan aplikasi kepada serpihan dan menambah pengepala lapisan pengangkutan pada setiap satu daripadanya.

Asas Pemindahan Data Boleh Dipercayai

Lapisan pengangkutan kemudiannya menghantar segmen ke lapisan rangkaian penghantar, di mana segmen itu dikapsulkan dalam paket lapisan rangkaian (datagram) dan dihantar. Pada bahagian penerima, lapisan rangkaian mengekstrak segmen lapisan pengangkutan daripada datagram dan menghantarnya ke lapisan pengangkutan. Seterusnya, lapisan pengangkutan memproses segmen yang diterima supaya datanya tersedia untuk aplikasi penerima.

Asas Pemindahan Data Boleh Dipercayai

Prinsip penghantaran data yang boleh dipercayai

Penghantaran data yang boleh dipercayai melalui saluran yang selamat sepenuhnya

Kes paling mudah. Bahagian penghantar hanya menerima data dari lapisan atas, mencipta paket yang mengandunginya, dan menghantarnya ke saluran.

pelayan

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 + надежный канал
    }
}

Pelanggan

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

Penghantaran data yang boleh dipercayai melalui saluran dengan kemungkinan ralat

Langkah seterusnya adalah untuk menganggap bahawa semua paket yang dihantar diterima dalam susunan di mana ia dihantar, tetapi bit di dalamnya mungkin rosak kerana fakta bahawa saluran kadangkala menghantar data dengan herotan.

Asas Pemindahan Data Boleh Dipercayai

Dalam kes ini, mekanisme berikut digunakan:

  • pengesanan ralat;
  • maklum balas;
  • penghantaran semula.

Protokol pemindahan data yang boleh dipercayai yang mempunyai mekanisme serupa untuk mengulangi penghantaran beberapa kali dipanggil protokol Automatic Repeat reQuest (ARQ).
Di samping itu, adalah wajar mempertimbangkan kemungkinan ralat dalam resit, apabila pihak yang menerima tidak akan menerima apa-apa maklumat tentang hasil pemindahan paket terakhir.
Penyelesaian kepada masalah ini, juga digunakan dalam TCP, adalah untuk menambah medan baharu pada paket data yang mengandungi nombor urutan paket.

Asas Pemindahan Data Boleh Dipercayai

Penghantaran data yang boleh dipercayai melalui saluran yang tidak boleh dipercayai tertakluk kepada herotan dan kehilangan paket

Bersama-sama dengan herotan, malangnya, terdapat kehilangan paket dalam rangkaian.
Dan untuk menyelesaikan masalah ini, mekanisme diperlukan:

  • menentukan fakta kehilangan paket;
  • penghantaran semula paket yang hilang kepada pihak yang menerima.

Di samping itu, sebagai tambahan kepada kehilangan pakej, adalah perlu untuk memperuntukkan kemungkinan kehilangan resit atau, jika tiada apa-apa yang hilang, penghantarannya dengan kelewatan yang ketara. Dalam semua kes, perkara yang sama dilakukan: paket dihantar semula. Untuk mengawal masa, mekanisme ini menggunakan pemasa undur, yang membolehkan anda menentukan akhir selang menunggu. Jadi dalam pakej bersih TCPKeepAlive ditetapkan kepada 15 saat secara lalai:

// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
    defaultTCPKeepAlive = 15 * time.Second
)

Bahagian penghantar perlu memulakan pemasa setiap kali paket dihantar (kedua-dua kali pertama dan kedua), mengendalikan gangguan daripada pemasa dan menghentikannya.

Jadi, kami telah membiasakan diri dengan konsep utama protokol pemindahan data yang boleh dipercayai:

  • jumlah semak;
  • nombor urutan pakej;
  • pemasa;
  • penerimaan positif dan negatif.

Tetapi bukan itu sahaja!

Protokol pemindahan data yang boleh dipercayai dengan saluran paip

Dalam varian yang telah kami pertimbangkan, protokol penghantaran yang boleh dipercayai adalah sangat tidak cekap. Ia mula "memperlahankan" penghantaran yang disediakan oleh saluran komunikasi apabila RTT meningkat. Untuk meningkatkan kecekapannya dan menggunakan kapasiti saluran komunikasi dengan lebih baik, saluran paip digunakan.

Asas Pemindahan Data Boleh Dipercayai

Penggunaan saluran paip membawa kepada:

  • meningkatkan julat nombor jujukan, kerana semua paket yang dihantar (kecuali untuk penghantaran semula) mesti dikenal pasti secara unik;
  • keperluan untuk meningkatkan penimbal pada bahagian pemancar dan penerima.

Julat nombor jujukan dan keperluan saiz penimbal bergantung pada tindakan yang diambil oleh protokol sebagai tindak balas kepada kerosakan paket, kehilangan dan kelewatan. Dalam kes saluran paip, terdapat dua kaedah untuk membetulkan ralat:

  • kembalikan N paket;
  • pengulangan terpilih.

Kembali N paket - protokol tetingkap gelongsor

Asas Pemindahan Data Boleh Dipercayai

Pengirim mesti menyokong tiga jenis acara:

  • panggilan melalui protokol peringkat lebih tinggi. Apabila fungsi penghantaran data dipanggil "dari atas", pihak penghantar terlebih dahulu menyemak tahap pengisian tetingkap (iaitu, kehadiran N mesej dihantar menunggu penerimaan resit). Jika tetingkap kosong, paket baharu dijana dan dihantar, dan nilai pembolehubah dikemas kini. Jika tidak, bahagian penghantar mengembalikan data ke lapisan atas, dan ini merupakan petunjuk tersirat bahawa tetingkap penuh. Lazimnya lapisan atas akan cuba menghantar data semula selepas beberapa ketika. Dalam aplikasi sebenar, penghantar mungkin sama ada menimbal data (bukannya menghantarnya dengan segera) atau mempunyai mekanisme penyegerakan (seperti semafor atau bendera) yang akan membenarkan lapisan atas memanggil fungsi hantar hanya apabila tetingkap kosong .
  • menerima pengesahan. Dalam protokol, untuk paket dengan nombor urutan N, pengakuan am dikeluarkan yang menunjukkan bahawa semua paket dengan nombor urutan sebelum N telah berjaya diterima.
  • tempoh menunggu telah tamat. Untuk menentukan fakta kehilangan dan kelewatan paket dan resit, protokol menggunakan pemasa. Jika selang masa tamat, pihak penghantar akan menghantar semula semua paket yang tidak diketahui.

Pengulangan terpilih

Apabila saiz tetingkap dan produk kelewatan penyebaran-proses adalah besar, sejumlah besar paket mungkin berada dalam perancangan. Dalam kes sedemikian, ralat paket tunggal boleh menyebabkan sejumlah besar paket dihantar semula, kebanyakannya tidak diperlukan.

Contoh

Top secara teori amalan dikumpul dalam pelaksanaan praktikal TCP. Dan jika seseorang tahu cara terbaik - dialu-alukan.

pelayan

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

Pelanggan

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

Output

Mekanisme untuk memastikan pemindahan dan penggunaan data yang boleh dipercayai

Mekanisme
Permohonan, komen

Periksa jumlah
Digunakan untuk mengesan ralat bit dalam paket yang dihantar

Pemasa
Mengira detik selang masa tamat dan menunjukkan apabila ia telah tamat tempoh. Yang terakhir bermaksud bahawa dengan tahap kebarangkalian yang tinggi paket atau resitnya hilang semasa penghantaran. Jika paket dihantar dengan kelewatan, tetapi tidak hilang (tamat tempoh pramatang selang masa tamat), atau resit hilang, penghantaran semula membawa kepada paket pendua pada bahagian penerima

Nombor siri
Digunakan untuk penomboran berurutan bagi paket data yang dihantar dari penghantar kepada penerima. Jurang dalam nombor urutan paket yang diterima membolehkan penerima mengesan kehilangan paket. Nombor jujukan paket yang sama bermakna bahawa paket adalah pendua antara satu sama lain

Pengesahan
Dijana oleh hujung penerima dan menunjukkan kepada hujung penghantaran bahawa paket atau kumpulan paket yang sepadan telah berjaya diterima. Biasanya pengakuan mengandungi nombor urutan paket yang berjaya diterima. Bergantung pada protokol, pengesahan individu dan kumpulan dibezakan

Pengesahan negatif
Digunakan oleh penerima untuk memaklumkan pengirim bahawa paket telah diterima secara tidak betul. Pengakuan negatif biasanya termasuk nombor urutan paket yang tidak diterima dengan betul

Tingkap, penghantar
Hadkan julat nombor jujukan yang boleh digunakan untuk menghantar paket. Multicast dan jabat tangan boleh meningkatkan pemprosesan protokol dengan ketara berbanding menunggu pengakuan. Seperti yang akan kita lihat, saiz tetingkap boleh dikira berdasarkan penerimaan dan keupayaan penampan hujung penerima, serta tahap beban rangkaian

Lebih banyak contoh menggunakan Go untuk rangkaian

В repositori.

Sumber: www.habr.com

Tambah komen