Kepada mereka yang
Secara ringkas
Artikel membincangkan asas penghantaran data yang boleh dipercayai, melaksanakan contoh pada
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.
Ini dilakukan dengan membelah (jika perlu) mesej lapisan aplikasi kepada serpihan dan menambah pengepala lapisan pengangkutan pada setiap satu daripadanya.
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.
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.
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.
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
// 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.
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
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
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
В
Sumber: www.habr.com