Всем привет, мы снова встретились, я ваш друг Цюаньчжаньцзюнь.
В предыдущем документе мы представили знания, связанные с IP, и краткое описание часто используемых функций в сетевом программировании Linux. В этой статье основное внимание уделяется конкретной связи UDP, чтобы подробно представить использование связи UDP, включая связь «точка-точка» и многоадресную рассылку. UDP-связь, вещание и т. д.
По сравнению с TCP, UDP — это метод связи без установления соединения, который не требует функциональных операций, таких как подключение, прослушивание и принятие, а также не требует поддержания состояний TCP-соединения, отключения и т. д. Конкретный процесс общения выглядит следующим образом:
Вышеописанный процесс связи относительно ясен. В процессе фактического использования необходимо обратить внимание на несколько моментов:
1. Когда мы пишем серверную UDP-программу, привязка является необходимым шагом, чтобы система могла знать, откуда или с какого порта наша программа Recvfrom хочет получить данные. Если у нас этого нет, данные не будут получены. по умолчанию. Конечно, после того, как наш сервер создает сокет, он активно отправляет данные, так что даже если мы не привязываемся, мы все равно можем получить данные. Просто система автоматически привязывает порт через нашу отправку. Это не так. То, что мы хотим, в реальном использовании не рекомендуется.
2. В описанной выше структуре связи клиент не использует операцию привязки. Это действительно так, поскольку клиент обычно выступает в качестве инициатора связи и активно отправляет данные. Как описано в пункте 1, этот процесс интеллектуально контролируется. Помогите нам записать информацию о порте. Когда сервер ответит данными, система будет знать, на какой порт следует перенаправить данные. Однако это не означает, что мы не можем активно выполнять операции связывания.
3. Что касается операции привязки на стороне сервера, то при наличии нескольких методов связи, таких как многоадресная рассылка и многоадресная рассылка, есть еще некоторые моменты, на которые необходимо обратить внимание. Мы опишем это в следующих главах.
В UDP несколько функций, участвующих в выполнении базовой связи, следующие:
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
int close(int fd);
Вышеупомянутые функции в принципе могут «узнать значение, взглянув на имя», но есть небольшая деталь (ее можно также назвать небольшой ямкой), которая требует особого внимания: параметр addrlen в sendto легко понять, он — это длина параметра struct sockaddr. Как правило, при использовании не возникает сомнений, но когда мы используем Recvfrom, нам нужно обратить внимание на параметр addrlen. Если нам не нужно заботиться об IP-информации отправителя, просто заполните его. в НУЛЕ.
recvfrom(sockfd, buf, len, flags, NULL, NULL);
Но когда нам нужно знать информацию об IP отправителя, нам нужно указать эти два параметра, которые используются либо для отправки информации об IP отправителя, либо для длины данных IP.
uint32_t addr_size;
struct sockaddr_in addr
recvfrom(socket, msg, msg_len, 0, (struct sockaddr *)&addr, &addr_size);
На первый взгляд, в приведенном выше коде нет ничего плохого. Обычное понимание заключается в том, что информация об IP отправителя существует в addr, а addr_size хранит длину данных addr. Однако в реальном использовании после такого вызова мы печатаем информацию в. addr, и это действительно неверная информация об IP или адресе, например 0.0.0.0. В чем причина? В описании на сайте этого человека содержится следующий абзац.
Подводя итог, мы должны инициализировать длину addr_size. Если установленная длина короче длины в addr, произойдет усечение, и полученная информация об IP будет неверной. Правильный способ ее использования:
uint32_t addr_size = sizeof(struct sockaddr_in);
struct sockaddr_in addr
recvfrom(socket, msg, msg_len, 0, (struct sockaddr *)&addr, &addr_size);
Таким образом, мы можем правильно получить информацию об IP.
Одноадресная рассылка и широковещательная рассылка — это две крайности: либо связь с одним хостом, либо связь с хостами во всей локальной сети. Однако в нашем реальном использовании обычно только некоторые хосты заинтересованы в данных связи, а не все хосты во всей локальной сети нуждаются в этих данных. В этом случае требуется многоадресная рассылка.
Адреса многоадресной рассылки специфичны, и для многоадресной рассылки используются адреса класса D. IP-адреса класса D представляют собой IP-адреса многоадресной рассылки, то есть IP-адреса между 224.0.0.0 и 239.255.255.255, и делятся на три категории: адреса многоадресной рассылки локального подключения, зарезервированные адреса многоадресной рассылки и адреса многоадресной рассылки с правами управления:
1. Локальный адрес многоадресной рассылки: от 224.0.0.0 до 224.0.0.255. Это адрес, зарезервированный для протоколов маршрутизации и других целей. Маршрутизатор не пересылает IP-пакеты, принадлежащие этому диапазону. ·
2. Зарезервированный адрес многоадресной рассылки: от 224.0.1.0 до 238.255.255.255, который может использоваться глобально (например, в Интернете) или в сетевых протоколах.
3. Адрес многоадресной рассылки с разрешением на управление: от 239.0.0.0 до 239.255.255.255, который можно использовать внутри организации. Он аналогичен частному IP-адресу и не может использоваться в Интернете. Диапазон многоадресной рассылки может быть ограничен.
Многоадресная рассылка реализована на основе базовой среды программирования UDP с использованием функцийetsockopt() иgetockopt(). Необходимо установить соответствующие параметры уровня IP (второй параметр — IPPROTO_IP). Его прототип следующий:
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
Общие параметры настройки многоадресной рассылки следующие:
в:
Опция IP_MULTICASE_TTL: установите тайм-аут, диапазон настройки значения optval: 0–255.
Опция IP_MULTICAST_IF: устанавливает сетевой интерфейс по умолчанию для многоадресной рассылки. Эти данные будут отправлены с данного сетевого интерфейса и будут игнорироваться другим сетевым интерфейсом.
Опции IP_ADD_MEMBERSHIP и IP_DROP_MEMBERSHIP: присоединиться или покинуть группу многоадресной рассылки, параметры которой являются структурой.
Базовый процесс программирования для использования многоадресной рассылки выглядит следующим образом:
(TBD)
Разница между широковещательной передачей UDP и обычной связью UDP не очень велика. Если вам нужно отправлять широковещательные сообщения, вам нужно настроить сокет только после создания сокета, чтобы разрешить отправку широковещательных сообщений.
int set_broadcast = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &set_broadcast,sizeof(set_broadcast));
1. В некоторых случаях нашей серверной программе необходимо одновременно использовать одноадресную, многоадресную и широковещательную рассылку, а общие программы будут использовать назначенные порты. Таким образом, в процессе реального использования программа часто сталкивается с такими проблемами:
Address already in use
Например, наш сервер транслирует свое существование в сети посредством широковещательной рассылки, сообщая другим хостам информацию о своем IP-адресе и методе связи с самим собой. После завершения широковещательной рассылки программа установит одноадресный клиент UDP и будет ждать отправки заинтересованными клиентами. информация. В настоящее время при сборке клиента часто появляется сообщение об указанной выше ошибке.
Решение следующее: (разрешить повторное использование порта)
int on = 1;
ret = setsockopt(udp_net_sta.socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
if (ret < 0)
{
perror("socket set SO_REUSEADDR failed");
}
2. В серверной программе после создания сокета происходит операция привязки, которая соответствует привязанному порту. Сомнений в этом нет, но при выборе привязанного IP-адреса мы обычно выбираем INADDR_ANY, поэтому никаких сомнений не будет. Проблема. Одноадресные и многоадресные данные могут быть получены нормально, но если мы укажем здесь фиксированный IP-адрес, мы сможем получать данные только с этого IP-адреса. Если нам также необходимо реализовать одноадресную, многоадресную и другие функции, вам необходимо создать несколько сокетов. чтобы добиться этого.
Заявление об авторских правах: Содержание этой статьи добровольно предоставлено пользователями Интернета, а мнения, выраженные в этой статье, представляют собой только точку зрения автора. Данный сайт лишь предоставляет услуги по хранению информации, не имеет никаких прав собственности и не несет соответствующей юридической ответственности. Если вы обнаружите на этом сайте какое-либо подозрительное нарушение авторских прав/незаконный контент, отправьте электронное письмо, чтобы сообщить. После проверки этот сайт будет немедленно удален.
Издатель: Лидер стека программистов полного стека, укажите источник для перепечатки: https://javaforall.cn/195954.html Исходная ссылка: https://javaforall.cn