7-bo‘lim

UDP

Transport qatlami nima uchun kerak, UDP sarlavhasi, datagramma chegaralari, hech qanday kafolat bermasligi va qachon aynan shu to'g'ri tanlov ekani.

🕑 9 daqiqa o‘qish 📄 801 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Eng sodda transport
  2. UDP sarlavhasi - 8 bayt
  3. Datagramma chegarasi saqlanadi
  4. Hech qanday kafolat yo'q
  5. UDP qachon to'g'ri tanlov?
  6. Xulosa

IP paketni kompyuterga yetkazadi. Lekin bitta kompyuterda o'nlab dastur ishlaydi - brauzer, pochta, o'yin. Paket qaysi dasturga tegishli?

Bu savolga transport qatlami javob beradi. Uning quroli - port raqami.

Eng sodda transport #

UDP - transport qatlamining eng sodda protokoli. U IP ga atigi ikki narsa qo'shadi:

  • port raqamlari (qaysi dasturga);
  • ixtiyoriy nazorat yig'indisi (buzilmaganmi).

Boshqa hech narsa. Kafolat yo'q, tartib yo'q, qayta yuborish yo'q.

Python
import socket

PORT = 9300

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("127.0.0.1", PORT))

mijoz = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# UDP da "ulanish" yo'q - shunchaki jo'natiladi
mijoz.sendto(b"salom", ("127.0.0.1", PORT))

malumot, kimdan = server.recvfrom(1024)
print("server oldi:", malumot.decode())
print("kimdan     :", kimdan[0], "portdan", kimdan[1] >= 1024)

# Javob ham shunchaki jo'natiladi
server.sendto(malumot.upper(), kimdan)
javob, _ = mijoz.recvfrom(1024)
print("mijoz oldi :", javob.decode())

mijoz.close()
server.close()
Natija
server oldi: salom
kimdan     : 127.0.0.1 portdan True
mijoz oldi : SALOM

SOCK_DGRAM - "datagramma soketi", ya'ni UDP. connect() ham, listen() ham, accept() ham yo'q. Bir tomon jo'natadi, ikkinchisi oladi.

UDP sarlavhasi - 8 bayt #

UDP sarlavhasi - jami 8 bayt Jo'natuvchi port 2 bayt Manzil porti 2 bayt Uzunlik 2 bayt Nazorat yig'indi 2 bayt Foydali yuk Taqqoslang: TCP sarlavhasi kamida 20 bayt UDP da tartib raqami ham, tasdiq ham, oyna ham yo'q - shuning uchun u shunchalik kichik
Sakkiz bayt - bu UDP ning butun qo'shimcha xarajati

Uni qo'lda yig'ib, keyin o'qib ko'ramiz:

Python
import struct

# UDP sarlavhasi - atigi 8 bayt
jonatuvchi_port = 51000
manzil_port = 53
yuk = b"so'rov ma'lumoti"
uzunlik = 8 + len(yuk)
nazorat = 0            # IPv4 da ixtiyoriy, 0 - "hisoblanmagan"

sarlavha = struct.pack("!HHHH", jonatuvchi_port, manzil_port,
                       uzunlik, nazorat)
datagramma = sarlavha + yuk

print("sarlavha uzunligi:", len(sarlavha), "bayt")
print("butun datagramma :", len(datagramma), "bayt")
print("o'n oltilikda    :", sarlavha.hex(" "))

# Endi teskari - o'qiymiz
jp, mp, uz, nz = struct.unpack("!HHHH", datagramma[:8])
print()
print("jo'natuvchi port:", jp)
print("manzil porti    :", mp)
print("uzunlik maydoni :", uz)
print("nazorat yig'indi:", nz)
print("yuk             :", datagramma[8:uz].decode())
Natija
sarlavha uzunligi: 8 bayt
butun datagramma : 24 bayt
o'n oltilikda    : c7 38 00 35 00 18 00 00

jo'natuvchi port: 51000
manzil porti    : 53
uzunlik maydoni : 24
nazorat yig'indi: 0
yuk             : so'rov ma'lumoti

00 35 - bu o'n oltilikda 53, ya'ni DNS porti. 11-bo'limda aynan shunday datagramma yasab, haqiqiy DNS serveriga yuboramiz.

Datagramma chegarasi saqlanadi #

Bu UDP ning eng muhim xususiyatlaridan biri: nima yuborsangiz, o'sha butunligicha keladi.

Python
import socket

PORT = 9301

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("127.0.0.1", PORT))
mijoz = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Uchta alohida datagramma jo'natamiz
for matn in [b"birinchi", b"ikkinchi", b"uchinchi"]:
    mijoz.sendto(matn, ("127.0.0.1", PORT))

# Har recvfrom AYNAN BITTA datagramma qaytaradi
for i in range(3):
    malumot, _ = server.recvfrom(1024)
    print(f"{i + 1}-o'qish: {malumot.decode()}  ({len(malumot)} bayt)")

# Katta bufer so'ralsa ham, ikkita datagramma birlashmaydi
mijoz.sendto(b"AAA", ("127.0.0.1", PORT))
mijoz.sendto(b"BBB", ("127.0.0.1", PORT))
malumot, _ = server.recvfrom(65535)
print()
print("65535 bayt so'radik, keldi:", malumot.decode())
print("chegara saqlandimi:", malumot == b"AAA")

mijoz.close()
server.close()
Natija
1-o'qish: birinchi  (8 bayt)
2-o'qish: ikkinchi  (8 bayt)
3-o'qish: uchinchi  (8 bayt)

65535 bayt so'radik, keldi: AAA
chegara saqlandimi: True

65 535 bayt so'radik, lekin faqat AAA keldi - chunki datagramma chegarasi buzilmaydi.

TCP da bu butunlay boshqacha

TCP - bu bayt oqimi, unda xabar chegarasi degan tushuncha yo'q.

TCP da AAA va BBB ni yuborsangiz, qabul qiluvchi bir recv da AAABBB ni olishi mumkin. Yoki AA, keyin ABBB.

Aynan shuning uchun TCP ustida ishlaydigan har bir protokol xabar chegarasini o'zi belgilashi kerak: uzunlik maydoni bilan yoki ajratuvchi belgi bilan.

HTTP buni Content-Length sarlavhasi bilan hal qiladi - 12-bo'limda ko'ramiz.

Hech qanday kafolat yo'q #

Endi UDP ning asosiy xususiyatini ko'rsatamiz: u yetib borgan- bormaganini tekshirmaydi.

Python
import socket

mijoz = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
mijoz.settimeout(1.0)

# Hech kim tinglamayotgan portga jo'natamiz
YOQ_PORT = 9399
natija = mijoz.sendto(b"kimdir bormi?", ("127.0.0.1", YOQ_PORT))

print("sendto xato berdimi:", "yoq")
print("jo'natilgan bayt   :", natija)

# Javob kutamiz - lekin javob beradigan hech kim yo'q
try:
    mijoz.recvfrom(1024)
    print("javob keldi")
except socket.timeout:
    print("javob kelmadi: kutish vaqti tugadi")
except ConnectionRefusedError:
    print("javob kelmadi: ICMP 'port yopiq' qaytdi")

mijoz.close()
Natija
sendto xato berdimi: yoq
jo'natilgan bayt   : 13
javob kelmadi: kutish vaqti tugadi

sendto muvaffaqiyatli qaytdi va 13 bayt yuborilganini aytdi - garchi u yerda hech kim bo'lmasa ham.

"Yuborildi" degani "yetib bordi" degani emas

UDP da sendto faqat bitta narsani bildiradi: ma'lumot operatsion tizimga topshirildi.

Undan keyin nima bo'lgani - yetib bordimi, yo'qoldimi, ikki marta keldimi - sendto ni umuman qiziqtirmaydi.

Shuning uchun UDP ustida ishlaydigan har bir dastur kafolatni o'zi qurishi kerak: tasdiq, qayta yuborish, tartib raqami.

Ya'ni ishonchlilik kerak bo'lsa, uni baribir yozishga to'g'ri keladi - shunchaki TCP dan past darajada.

Kod ikkita istisnoni ushlaydi, chunki javob operatsion tizimga bog'liq: ba'zi tizimlar ICMP "port yopiq" xabarini dasturga yetkazadi, ba'zilari esa yo'q. Bizda kutish vaqti tugadi.

UDP qachon to'g'ri tanlov? #

HolatNima uchun UDP
DNS so'roviBitta so'rov, bitta javob - ulanish qurish qimmat
Video va ovozKechikkan kadr kerak emas, yangisi allaqachon keldi
O'yinlarEski holatni qayta yuborishdan foyda yo'q
Jurnal va o'lchovlarBittasi yo'qolsa - muammo emas
DHCPIP manzilingiz hali yo'q - TCP qura olmaysiz

Umumiy qoida: eskirgan ma'lumot foydasiz bo'lsa, UDP to'g'ri tanlov.

Video qo'ng'irog'ida uch soniya oldingi kadrni qayta yuborish faqat zarar keltiradi - u allaqachon kerak emas, lekin navbatni band qiladi.

QUIC - UDP ustidagi yangi avlod

HTTP/3 ham UDP ustida ishlaydi. G'alati tuyulishi mumkin - veb uchun ishonchlilik-ku kerak?

Gap shundaki, QUIC ishonchlilikni o'zi quradi, lekin uni zamonaviyroq qilib quradi: ulanish tezroq o'rnatiladi, shifrlash ichiga qurilgan, bitta oqimdagi yo'qotish boshqalarini to'xtatib qo'ymaydi.

TCP ni o'zgartirish deyarli imkonsiz edi - u operatsion tizim yadrosida va dunyodagi barcha qurilmalarda. UDP ustiga yangi protokol qurish esa ancha oson bo'ldi.

Buni 13-bo'limda batafsil ko'ramiz.

UDP va kuchaytiruvchi hujumlar

UDP da jo'natuvchi manzilini tekshirib bo'lmaydi: paketda "men falonchiman" deb yozilgan narsa shunchaki qabul qilinadi.

Hujumchi shu bilan foydalanadi: kichik so'rovga katta javob beradigan serverga murojaat qiladi va jo'natuvchi sifatida qurbonning manzilini yozadi. Javob qurbonga ketadi.

Shuning uchun ochiq UDP xizmatlarini internetga chiqarish xavfli. Himoya usullari:

ChoraFoydasi
Javobni so'rovdan katta qilmaslikKuchaytirish yo'qoladi
So'rov tezligini cheklashHujum sekinlashadi
Faqat ichki tarmoqqa ochishTashqaridan foydalanib bo'lmaydi

Agar o'z UDP xizmatingizni yozsangiz, javob hajmini albatta cheklang.

Amaliy topshiriq
  1. UDP echo misolini ishga tushiring.
  2. Serverni ishga tushirmasdan mijozni ishlating - nima bo'ldi?
  3. Datagramma chegarasi misolini ishga tushiring.
  4. Beshta datagramma yuborib, faqat uchtasini o'qing.
  5. recvfrom(2) deb chaqiring - qolgan baytlar nima bo'ldi?
  6. UDP sarlavhasini qo'lda yig'ing va port raqamini o'zgartiring.
  7. !HHHH ni !HHH ga o'zgartiring va xatoni o'qing.
  8. Kafolat yo'qligi misolini ishga tushiring.
  9. UDP ustida oddiy "tasdiq" mexanizmini yozing.
  10. O'z loyihangizda UDP mos keladigan bitta holatni toping.

Xulosa #

  • Transport qatlami paketni qaysi dasturga tegishli ekanini aniqlaydi.
  • Buning uchun port raqami ishlatiladi.
  • UDP - eng sodda transport: portlar va ixtiyoriy nazorat yig'indisi.
  • Sarlavhasi atigi 8 bayt (TCP da kamida 20).
  • UDP da ulanish yo'q: connect, listen, accept kerak emas.
  • Datagramma chegarasi saqlanadi - nima yuborilsa, o'shanday keladi.
  • TCP esa bayt oqimi: xabar chegarasini protokol o'zi belgilashi kerak.
  • sendto muvaffaqiyat qaytarsa ham, paket yetib borganini bildirmaydi.
  • UDP eskirgan ma'lumot foydasiz bo'lgan joyda to'g'ri: video, o'yin, DNS.
  • Jo'natuvchi manzilini soxtalashtirish oson - UDP xizmatida javob hajmini cheklang.

Keyingi bo'limda ishonchlilikni o'zi ta'minlaydigan protokolni ko'ramiz - TCP.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.