Реализуем несколько программ: talker.c и listener.c
-
listener(сервер) запускается и ожидает входящих пакетов на порте4950. -
talker(клиент) отправляет на этот порт сообщение из командой строки.
Так как UDP-сокеты являются connectionless и просто отправляют пакеты, несмотря на доступность получателя, мы реализуем и клиент и сервер с использованием IPv6.
Это позволит избежать ситуации, когда клиент запущен на одной версии протокола, а сервер на другой, в этом случае пакет просто не будет получен.
В случае с TCP, когда клиент и сервер на разных протоколах (IPv6/IPv4), в системных вызовах (например,
accept()) будет соответствующая ошибка. Хороший пример обработки ошибок, со стороны TCP.
В listener.c обратите внимание, что в отличии от TCP-сервера, мы используем SOCK_DGRAM. Также, UDP-серверу не требуется вызывать listen() и accept(), он просто вызывает recvfrom() и ждет пакетов от клиента:
int num_bytes = recvfrom(sockfd, buf, MAXBUFLEN - 1, 0, (struct sockaddr*)&their_addr, &addr_len);Реализация talker.c просто отправляет байты по заданному адресу. UDP-клиент не волнует, получил ли пакеты получатель или нет, он их просто отпрвляет. Помните, что UDP не гарантирует доставку пакетов.
В одном терминале запустим listener:
$ ./listener
listener: waiting to recvfrom...В другом talker, передав ему адрес и сообщение:
$ ./talker localhost heyMan
talker: sent 6 bytes to localhostВ listener сообщение получено:
# ...
listener: got packet from ::1
listener: packet is 6 bytes long
listener: packet contains "heyMan"talker можно запускать и без включенного сервера, пакеты он отправит, но они просто исчезнут, ибо некому их получать:
$ ./talker localhost heyMan
talker: sent 6 bytes to localhost
$ ./talker localhost heyMan
talker: sent 6 bytes to localhost
$ ./talker localhost heyMan
talker: sent 6 bytes to localhost