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.
Ushbu bo‘lim mundarijasi
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.
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()
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 #
Uni qo'lda yig'ib, keyin o'qib ko'ramiz:
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())
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.
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()
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 - 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.
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()
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.
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? #
| Holat | Nima uchun UDP |
|---|---|
| DNS so'rovi | Bitta so'rov, bitta javob - ulanish qurish qimmat |
| Video va ovoz | Kechikkan kadr kerak emas, yangisi allaqachon keldi |
| O'yinlar | Eski holatni qayta yuborishdan foyda yo'q |
| Jurnal va o'lchovlar | Bittasi yo'qolsa - muammo emas |
| DHCP | IP 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.
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 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:
| Chora | Foydasi |
|---|---|
| Javobni so'rovdan katta qilmaslik | Kuchaytirish yo'qoladi |
| So'rov tezligini cheklash | Hujum sekinlashadi |
| Faqat ichki tarmoqqa ochish | Tashqaridan foydalanib bo'lmaydi |
Agar o'z UDP xizmatingizni yozsangiz, javob hajmini albatta cheklang.
- UDP echo misolini ishga tushiring.
- Serverni ishga tushirmasdan mijozni ishlating - nima bo'ldi?
- Datagramma chegarasi misolini ishga tushiring.
- Beshta datagramma yuborib, faqat uchtasini o'qing.
recvfrom(2)deb chaqiring - qolgan baytlar nima bo'ldi?- UDP sarlavhasini qo'lda yig'ing va port raqamini o'zgartiring.
!HHHHni!HHHga o'zgartiring va xatoni o'qing.- Kafolat yo'qligi misolini ishga tushiring.
- UDP ustida oddiy "tasdiq" mexanizmini yozing.
- 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,acceptkerak emas. - Datagramma chegarasi saqlanadi - nima yuborilsa, o'shanday keladi.
- TCP esa bayt oqimi: xabar chegarasini protokol o'zi belgilashi kerak.
sendtomuvaffaqiyat 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.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.