Kwa wale ambao
Kwa kifupi
Makala inazungumzia misingi ya maambukizi ya data ya kuaminika, hutumia mifano kwenye
Itifaki ya safu ya usafiri
Hutoa muunganisho wa kimantiki kati ya michakato ya programu inayoendeshwa kwenye wapangishaji tofauti. Kwa mtazamo wa programu, muunganisho wa kimantiki unaonekana kama chaneli inayounganisha moja kwa moja michakato.
Hii inafanywa kwa kugawanyika (ikiwa ni lazima) ujumbe wa safu ya programu katika vipande na kuongeza kichwa cha safu ya usafiri kwa kila mmoja wao.
Safu ya usafiri kisha hupitisha sehemu hiyo kwa safu ya mtandao ya mtumaji, ambapo sehemu hiyo imefungwa kwenye pakiti ya safu ya mtandao (datagram) na kutumwa. Katika mwisho wa kupokea, safu ya mtandao hutoa sehemu ya safu ya usafiri kutoka kwa datagram na kuipitisha hadi safu ya usafiri. Ifuatayo, safu ya usafirishaji huchakata sehemu iliyopokelewa ili data yake ipatikane kwa programu inayopokea.
Kanuni za usambazaji wa data za kuaminika
Usambazaji wa data unaotegemewa kupitia chaneli salama kabisa
Kesi rahisi zaidi. Upande wa kutuma hupokea tu data kutoka kwa safu ya juu, huunda pakiti iliyo nayo, na kuituma kwa kituo.
Seva
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 + надежный канал
}
}
Mteja
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)
}
}
Usambazaji wa data unaotegemewa kupitia kituo na hitilafu zinazowezekana
Hatua inayofuata ni kudhani kwamba pakiti zote zinazopitishwa zinapokelewa kwa utaratibu ambao zilitumwa, lakini bits ndani yao zinaweza kuharibiwa kutokana na ukweli kwamba kituo wakati mwingine hupeleka data kwa uharibifu.
Katika kesi hii, taratibu zifuatazo hutumiwa:
- kugundua makosa;
- maoni;
- kusambaza tena.
Itifaki za uhamishaji data zinazotegemewa ambazo zina mbinu sawa za kurudia utumaji mara nyingi huitwa itifaki za Kurudia Kurudia Kiotomatiki (ARQ).
Zaidi ya hayo, inafaa kuzingatia uwezekano wa makosa katika risiti, wakati mpokeaji hatapokea taarifa yoyote kuhusu matokeo ya uhamisho wa pakiti ya mwisho.
Suluhisho la tatizo hili, pia linatumika katika TCP, ni kuongeza sehemu mpya kwenye pakiti ya data iliyo na nambari ya mlolongo wa pakiti.
Usambazaji wa data unaotegemewa kupitia chaneli isiyotegemewa chini ya upotoshaji na upotevu wa pakiti
Pamoja na kupotosha, kwa bahati mbaya, kuna upotezaji wa pakiti kwenye mtandao.
Na ili kutatua tatizo hili, taratibu zinahitajika:
- kuamua ukweli wa upotezaji wa pakiti;
- uwasilishaji upya wa pakiti zilizopotea kwa mpokeaji.
Zaidi ya hayo, pamoja na hasara ya mfuko, ni muhimu kutoa kwa uwezekano wa kupoteza risiti au, ikiwa hakuna kitu kinachopotea, utoaji wake kwa kuchelewa kwa kiasi kikubwa. Katika hali zote, kitu kimoja kinafanyika: pakiti inatumwa tena. Ili kudhibiti wakati, utaratibu huu hutumia kipima muda cha kuhesabu, ambacho hukuruhusu kuamua mwisho wa muda wa kusubiri. Kwa hivyo kwenye kifurushi
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const (
defaultTCPKeepAlive = 15 * time.Second
)
Upande wa kutuma unahitaji kuanzisha kipima muda kila wakati pakiti inapotumwa (ya kwanza na ya pili), shughulikia kukatizwa na kipima muda na usitishe.
Kwa hivyo, tumezoea dhana kuu za itifaki za uhamishaji data za kuaminika:
- hundi;
- nambari za mlolongo wa vifurushi;
- vipima muda;
- risiti chanya na hasi.
Lakini si hivyo tu!
Itifaki ya kuaminika ya uhamishaji data na bomba
Katika tofauti ambayo tayari tumezingatia, itifaki ya utoaji wa kuaminika haifai sana. Huanza "kupunguza kasi" upitishaji unaotolewa na njia ya mawasiliano kadri RTT inavyoongezeka. Ili kuongeza ufanisi wake na kutumia vyema uwezo wa njia ya mawasiliano, bomba hutumiwa.
Matumizi ya bomba husababisha:
- kuongeza idadi ya nambari za mlolongo, kwa kuwa pakiti zote zilizotumwa (isipokuwa kwa retransmissions) lazima zitambuliwe kipekee;
- hitaji la kuongeza buffers kwenye pande za kupitisha na kupokea.
Safu ya nambari ya mfuatano na mahitaji ya saizi ya bafa hutegemea hatua ambazo itifaki inachukua ili kukabiliana na upotovu, upotevu na ucheleweshaji wa pakiti. Katika kesi ya bomba, kuna njia mbili za kurekebisha makosa:
- rudisha pakiti za N nyuma;
- marudio ya kuchagua.
Kurudi nyuma kwa pakiti N - itifaki ya dirisha ya kuteleza
Mtumaji lazima aauni aina tatu za matukio:
- piga simu kwa itifaki ya kiwango cha juu. Wakati kazi ya kutuma data inaitwa "kutoka juu", upande wa kutuma kwanza huangalia kiwango cha kujaza kwa dirisha (yaani, uwepo wa ujumbe uliotumwa wa N unaosubiri kupokea risiti). Ikiwa dirisha ni tupu, pakiti mpya hutolewa na kupitishwa, na maadili ya kutofautiana yanasasishwa. Vinginevyo, upande wa kutuma unarudisha data kwenye safu ya juu, na hii ni dalili kamili kwamba dirisha limejaa. Kwa kawaida safu ya juu itajaribu kusambaza data tena baada ya muda fulani. Katika programu-tumizi halisi, mtumaji anaweza aidha kuhifadhi data (badala ya kuituma mara moja) au kuwa na utaratibu wa kusawazisha (kama vile semaphore au bendera) ambayo ingeruhusu safu ya juu kuita kazi ya kutuma tu wakati dirisha liko tupu. .
- kupokea uthibitisho. Katika itifaki, kwa pakiti yenye nambari ya mlolongo N, uthibitisho wa jumla unatolewa unaoonyesha kwamba pakiti zote zilizo na nambari za mlolongo zilizotangulia N zilipokelewa kwa ufanisi.
- muda wa kusubiri umekwisha. Kuamua ukweli wa hasara na ucheleweshaji wa pakiti na risiti, itifaki hutumia timer. Ikiwa muda wa kuisha utaisha, upande unaotuma hutuma tena pakiti zote ambazo hazijatambuliwa.
marudio ya kuchagua
Wakati saizi ya dirisha na bidhaa ya ucheleweshaji wa uenezi ni kubwa, idadi kubwa ya pakiti inaweza kuwa kwenye bomba. Katika hali hiyo, kosa moja la pakiti inaweza kusababisha idadi kubwa ya pakiti kupitishwa tena, ambazo nyingi hazikuhitajika.
Mfano
Top
Seva
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"))
}
}
Mteja
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)
}
}
Pato
Taratibu za kuhakikisha uhamishaji na utumiaji wa data unaotegemewa
Mfumo
Maombi, maoni
Angalia jumla
Inatumika kugundua hitilafu kidogo katika pakiti iliyopitishwa
Muda
Huhesabu muda wa kuisha na huonyesha muda wake umeisha. Mwisho unamaanisha kuwa kwa kiwango kikubwa cha uwezekano pakiti au risiti yake inapotea wakati wa maambukizi. Ikiwa pakiti itawasilishwa kwa kuchelewa, lakini haijapotea (kuisha mapema kwa muda wa kuisha), au risiti imepotea, uwasilishaji upya husababisha pakiti ya nakala kwenye upande wa kupokea.
Nambari ya serial
Inatumika kwa kuweka nambari mfuatano za pakiti za data zinazotumwa kutoka kwa mtumaji hadi kwa mpokeaji. Mapungufu katika nambari za mlolongo wa pakiti zilizopokelewa huruhusu mpokeaji kugundua upotezaji wa pakiti. Nambari sawa za mlolongo wa pakiti inamaanisha kuwa pakiti ni nakala za kila mmoja
Uthibitisho
Imetolewa na mwisho wa upokeaji na kuonyesha hadi mwisho wa kutuma kwamba pakiti au kikundi cha pakiti kinacholingana kimepokelewa kwa ufanisi. Kwa kawaida kibali huwa na nambari za mfuatano wa pakiti zilizopokelewa kwa ufanisi. Kulingana na itifaki, uthibitisho wa mtu binafsi na wa kikundi hutofautishwa
Uthibitisho hasi
Inatumiwa na mpokeaji kumjulisha mtumaji kwamba pakiti ilipokelewa vibaya. Kukiri hasi kawaida hujumuisha nambari ya mfuatano wa pakiti ambayo haikupokelewa kwa usahihi
Dirisha, conveyorization
Punguza safu ya nambari za mfuatano ambazo zinaweza kutumika kusambaza pakiti. Multicast na handshake inaweza kwa kiasi kikubwa kuongeza throughput itifaki ikilinganishwa na kusubiri kwa shukrani. Kama tutakavyoona, saizi ya dirisha inaweza kuhesabiwa kulingana na uwezo wa mapokezi na buffering ya mwisho wa kupokea, pamoja na kiwango cha mzigo wa mtandao.
Mifano zaidi ya kutumia Go kwa mitandao
В
Chanzo: mapenzi.com