UDP
Материал из Xgu.ru
UDP (User Datagram Protocol) — один из важнейших протоколов стека TCP/IP. В соответствии с 7-уровневой моделью OSI работает на четвёртом, транспортном уровне.
Содержание |
[править] Потеря UDP-пакетов
Есть несколько причин, почему UDP-пакеты могут не доходить до адресата. Кроме собственно потерь на нижележащем уровне (физическом, канальном или сетевом), они могут отбрасываться уже на собственно уровне UDP.
В Linux, если пакет видится tcpdump-ом, но не видится приложением, тому может быть несколько причин:
- Контрольная сумма UDP-пакета неверна;
- Пакет убирается фильтром пакетов netfilter;
- Пакет убирается фильтром rp_filter[1];
- Приложение не успевает справиться с потоком пакетов, входящий буфер переполняется.
Проверить контрольную сумму можно с помощью tcpdump:
$ sudo tcpdump -i eth0 -vvv -nn udp dst port 53 tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 17:04:48.145904 IP (tos 0×0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 61) 10.0.0.2.56497 > 10.0.0.1.53: [bad udp cksum 0x8f54 -> 0xb8fc!] 30234+ AAAA? www.twitter.com. (33) 17:04:48.145925 IP (tos 0×0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 61) 10.0.0.2.56497 > 10.0.0.1.53: [bad udp cksum 0x224d -> 0x2604!] 30234+ AAAA? www.twitter.com. (33)
Чаще всего такая проблема возникает из-за TCO (TCP offloading). Выключить его и перепроверить можно так:
# ethtool -K eth0 tx off rx off
Подробно данная проблема описана здесь:
Ещё на эту тему:
- http://wiki.wireshark.org/CaptureSetup/Offloading
- When is full packet capture NOT full packet capture? (англ.)
- Wireshark User's Guide — Checksums (англ.)
Подробнее о том, как рассчитывается контрольная сумма в UDP-пакетах:
- UDP checksum calculation (англ.)
Игнорировать ошибки в контрольной сумме можно заставить битом SO_NO_CHECK сокета[2].
[править] Программирование UDP-сокетов
[править] Python
Клиент:
import socket UDP_IP = "127.0.0.1" UDP_PORT = 5005 MESSAGE = "Hello, World!" sock = socket.socket(socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
Сервер:
import socket UDP_IP = "127.0.0.1" UDP_PORT = 5005 sock = socket.socket(socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP sock.bind((UDP_IP, UDP_PORT)) while True: data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes print "received message:", data
Подробнее:
- https://wiki.python.org/moin/UdpCommunication
- http://www.binarytides.com/programming-udp-sockets-in-python/
Работа с широковещательными пакетами: