Сокеты UDP/датаграмм¶
Стабильность: 2 – Стабильная
АПИ является удовлетворительным. Совместимость с NPM имеет высший приоритет и не будет нарушена кроме случаев явной необходимости.
Модуль node:dgram реализует сокеты UDP-датаграмм.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Класс: dgram.Socket¶
- Наследует:
<EventEmitter>
Инкапсулирует работу с датаграммами.
Новые экземпляры dgram.Socket создаются через dgram.createSocket(). Ключевое слово new не используется для создания экземпляров dgram.Socket.
Событие: 'close'¶
Событие 'close' испускается после закрытия сокета вызовом close(). После этого на сокете больше не будут испускаться события 'message.
Событие: 'connect'¶
Событие 'connect' испускается после того, как сокет связан с удалённым адресом в результате успешного вызова connect().
Событие: 'error'¶
exception<Error>
Событие 'error' испускается при любой ошибке. Обработчику передаётся один объект Error.
Событие: 'listening'¶
Событие 'listening' испускается, когда dgram.Socket получает адрес и может принимать данные. Это происходит явно при socket.bind() или неявно при первой отправке данных через socket.send(). Пока dgram.Socket не слушает, низкоуровневые ресурсы не созданы, и вызовы вроде socket.address() и socket.setTTL() завершатся ошибкой.
Событие: 'message'¶
Добавлено в: v0.1.99
Событие 'message' испускается, когда на сокете доступна новая датаграмма. Обработчику передаются два аргумента: msg и rinfo.
Если исходный адрес входящего пакета — IPv6 link-local, к имени интерфейса добавляется к полю address. Например, пакет, принятый на интерфейсе en0, может иметь поле адреса 'fe80::2618:1234:ab11:3b9c%en0', где '%en0' — имя интерфейса как суффикс zone ID.
socket.addMembership(multicastAddress[, multicastInterface])¶
Указывает ядру присоединиться к multicast-группе по заданным multicastAddress и multicastInterface с опцией сокета IP_ADD_MEMBERSHIP. Если аргумент multicastInterface не указан, ОС выберет один интерфейс и добавит членство на нём. Чтобы добавить членство на каждом доступном интерфейсе, вызывайте addMembership несколько раз — по разу на интерфейс.
При вызове на несвязанном сокете метод неявно привязывается к случайному порту на всех интерфейсах.
При совместном использовании UDP-сокета несколькими воркерами cluster socket.addMembership() нужно вызывать только один раз, иначе возникнет ошибка EADDRINUSE:
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])¶
Указывает ядру присоединиться к source-specific multicast-каналу по заданным sourceAddress и groupAddress, используя multicastInterface и опцию сокета IP_ADD_SOURCE_MEMBERSHIP. Если аргумент multicastInterface не указан, ОС выберет интерфейс и добавит членство на нём. Чтобы добавить членство на каждом интерфейсе, вызывайте socket.addSourceSpecificMembership() несколько раз — по разу на интерфейс.
При вызове на несвязанном сокете метод неявно привязывается к случайному порту на всех интерфейсах.
socket.address()¶
- Возвращает:
<Object>
Возвращает объект с адресной информацией сокета. Для UDP-сокета в объекте будут свойства address, family и port.
Метод выбрасывает EBADF, если вызван на несвязанном сокете.
socket.bind([port][, address][, callback])¶
port<integer>address<string>callback<Function>без параметров. Вызывается по завершении привязки.
Для UDP-сокета заставляет dgram.Socket принимать датаграммы на указанном port и необязательном address. Если port не задан или равен 0, ОС попытается привязаться к случайному порту. Если address не задан, ОС попытается слушать на всех адресах. После успешной привязки испускается событие 'listening' и вызывается необязательный callback.
Одновременно задать обработчик 'listening' и передать callback в socket.bind() не вредно, но мало что даёт.
Привязанный датаграммный сокет удерживает процесс Node.js запущенным для приёма датаграмм.
При ошибке привязки генерируется событие 'error'. В редких случаях (например привязка закрытого сокета) может быть выброшен Error.
Пример UDP-сервера на порту 41234:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
socket.bind(options[, callback])¶
options<Object>Обязателен. Поддерживает свойства:callback<Function>
Для UDP-сокета заставляет dgram.Socket принимать датаграммы на указанном port и необязательном address, переданных как свойства объекта options первым аргументом. Если port не задан или равен 0, ОС попытается привязаться к случайному порту. Если address не задан, ОС попытается слушать на всех адресах. После привязки испускается 'listening' и вызывается необязательный callback.
Объект options может содержать свойство fd. Если задан fd больше 0, оборачивается существующий сокет с данным файловым дескриптором. В этом случае свойства port и address игнорируются.
Одновременно задать обработчик 'listening' и callback для socket.bind() не вредно, но мало что даёт.
Объект options может содержать дополнительное свойство exclusive, используемое с модулем cluster. При exclusive равном false (по умолчанию) воркеры cluster используют один нижележащий дескриптор сокета и могут совместно обрабатывать соединения. При exclusive равном true дескриптор не разделяется, и попытка разделить порт приводит к ошибке. Создание dgram.Socket с опцией reusePort: true делает exclusive всегда true при вызове socket.bind().
Привязанный датаграммный сокет удерживает процесс Node.js для приёма датаграмм.
При ошибке привязки генерируется 'error'. В редких случаях может быть выброшен Error.
Ниже пример сокета с эксклюзивным портом.
1 2 3 4 5 | |
socket.close([callback])¶
callback<Function>Вызывается после закрытия сокета.
Закрывает нижележащий сокет и прекращает приём данных. Если передан callback, он добавляется как обработчик события 'close'.
socket[Symbol.asyncDispose]()¶
Вызывает socket.close() и возвращает промис, который выполняется после закрытия сокета.
socket.connect(port[, address][, callback])¶
port<integer>address<string>callback<Function>Вызывается при успешном соединении или при ошибке.
Связывает dgram.Socket с удалённым адресом и портом. Каждое сообщение, отправляемое этим дескриптором, уходит на этот адрес. Сокет принимает сообщения только от этого удалённого узла. Повторный вызов connect() на уже подключённом сокете приводит к исключению ERR_SOCKET_DGRAM_IS_CONNECTED. Если address не задан, по умолчанию используется '127.0.0.1' (для udp4) или '::1' (для udp6). После установления соединения испускается 'connect' и вызывается необязательный callback. При ошибке вызывается callback или, если это невозможно, испускается 'error'.
socket.disconnect()¶
Синхронная функция, отсоединяющая подключённый dgram.Socket от удалённого адреса. Вызов disconnect() на несвязанном или уже отсоединённом сокете даёт исключение ERR_SOCKET_DGRAM_NOT_CONNECTED.
socket.dropMembership(multicastAddress[, multicastInterface])¶
Указывает ядру покинуть multicast-группу по multicastAddress с опцией сокета IP_DROP_MEMBERSHIP. Ядро вызывает это автоматически при закрытии сокета или завершении процесса, поэтому приложениям редко нужно вызывать метод вручную.
Если multicastInterface не указан, ОС попытается снять членство на всех подходящих интерфейсах.
socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])¶
Указывает ядру покинуть source-specific multicast-канал по заданным sourceAddress и groupAddress с опцией IP_DROP_SOURCE_MEMBERSHIP. Ядро вызывает это автоматически при закрытии сокета или завершении процесса.
Если multicastInterface не указан, ОС попытается снять членство на всех подходящих интерфейсах.
socket.getRecvBufferSize()¶
- Возвращает:
<number>размер буфера приёма сокетаSO_RCVBUFв байтах.
Метод выбрасывает ERR_SOCKET_BUFFER_SIZE на несвязанном сокете.
socket.getSendBufferSize()¶
- Возвращает:
<number>размер буфера отправки сокетаSO_SNDBUFв байтах.
Метод выбрасывает ERR_SOCKET_BUFFER_SIZE на несвязанном сокете.
socket.getSendQueueSize()¶
- Возвращает:
<number>Число байт в очереди на отправку.
socket.getSendQueueCount()¶
- Возвращает:
<number>Число запросов на отправку в очереди, ожидающих обработки.
socket.ref()¶
- Возвращает:
<dgram.Socket>
По умолчанию привязка сокета удерживает процесс Node.js от завершения, пока сокет открыт. socket.unref() исключает сокет из подсчёта ссылок, удерживающего процесс. socket.ref() снова включает сокет в подсчёт и восстанавливает поведение по умолчанию.
Повторные вызовы socket.ref() не меняют поведение дополнительно.
socket.ref() возвращает ссылку на сокет для цепочки вызовов.
socket.remoteAddress()¶
- Возвращает:
<Object>
Возвращает объект с address, family и port удалённого узла. Если сокет не подключён, выбрасывается ERR_SOCKET_DGRAM_NOT_CONNECTED.
socket.send(msg[, offset, length][, port][, address][, callback])¶
Добавлено в: v0.1.99
msg<Buffer>|<TypedArray>|<DataView>|<string>|<Array>Отправляемое сообщение.offset<integer>Смещение в буфере, с которого начинается сообщение.length<integer>Число байт в сообщении.port<integer>Порт назначения.address<string>Имя хоста или IP-адрес назначения.callback<Function>Вызывается после отправки сообщения.
Отправляет датаграмму через сокет. Для сокетов без соединения нужно указать port и address назначения. Подключённые сокеты используют связанный удалённый узел, аргументы port и address задавать нельзя.
Аргумент msg — отправляемое сообщение. Поведение зависит от типа. Если msg — Buffer, TypedArray или DataView, offset и length задают смещение в буфере и число байт сообщения. Если msg — строка, она преобразуется в Buffer с кодировкой 'utf8'. Для символов в нескольких байтах offset и length считаются по byte length, а не по позиции символа. Если msg — массив, offset и length указывать нельзя.
Аргумент address — строка. Если это имя хоста, для разрешения используется DNS. Если address не задан или равен null/undefined, по умолчанию берутся '127.0.0.1' (udp4) или '::1' (udp6).
Если сокет ещё не был привязан вызовом bind, ему назначается случайный порт и адрес «все интерфейсы» ('0.0.0.0' для udp4, '::0' для udp6).
Необязательный callback можно использовать для сообщения об ошибках DNS или чтобы узнать, когда безопасно повторно использовать объект буфера. Поиск в DNS откладывает отправку минимум на один тик цикла событий Node.js.
Надёжно убедиться, что датаграмма отправлена, можно только через callback. При ошибке и наличии callback ошибка передаётся первым аргументом в callback. Без callback ошибка испускается как событие 'error' на сокете.
offset и length необязательны, но если используется один из них, нужны оба. Они поддерживаются только если первый аргумент — Buffer, TypedArray или DataView.
На несвязанном сокете метод выбрасывает ERR_SOCKET_BAD_PORT.
Пример отправки UDP-пакета на порт на localhost:
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 | |
Пример отправки UDP-пакета из нескольких буферов на порт на 127.0.0.1:
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 6 7 8 9 | |
Отправка нескольких буферов может быть быстрее или медленнее в зависимости от приложения и ОС. Сравнивайте на бенчмарках для вашего случая. Обычно отправка нескольких буферов быстрее.
Пример отправки UDP-пакета через подключённый к порту на localhost сокет:
1 2 3 4 5 6 7 8 9 10 | |
1 2 3 4 5 6 7 8 9 10 | |
Замечание о размере UDP-датаграммы¶
Максимальный размер датаграммы IPv4/v6 зависит от MTU (максимальная единица передачи) и размера поля Payload Length.
-
Поле
Payload Lengthимеет ширину 16 бит, поэтому обычная полезная нагрузка не может превышать 64K октетов вместе с заголовками интернета и данными (65 507 байт = 65 535 − 8 байт UDP − 20 байт IP); это обычно для петлевого интерфейса, но такие длинные датаграммы непрактичны для большинства хостов и сетей. -
MTU— максимальный размер, который поддерживает технология канального уровня для датаграмм. Для любого канала IPv4 требует минимумMTU68 октетов, рекомендуемыйMTUдля IPv4 — 576 (часто для коммутируемого доступа), целиком или фрагментами.Для IPv6 минимальный
MTU— 1280 октетов. Обязательный минимальный размер буфера сборки фрагментов — 1500 октетов. 68 октетов мало: у большинства сетей, например Ethernet-сетей,MTUне меньше 1500.
Заранее невозможно узнать MTU всех участков пути пакета. Если датаграмма больше MTU получателя, она не дойдёт: пакет отбрасывается без уведомления источника.
socket.setBroadcast(flag)¶
flag<boolean>
Устанавливает или сбрасывает опцию сокета SO_BROADCAST. При true UDP-пакеты можно отправлять на широковещательный адрес локального интерфейса.
На несвязанном сокете метод выбрасывает EBADF.
socket.setMulticastInterface(multicastInterface)¶
multicastInterface<string>
Все упоминания scope здесь относятся к IPv6 Zone Indexes, определённым в RFC 4007. В строковой форме IP с индексом области записывается как 'IP%scope', где scope — имя интерфейса или его номер.
Задаёт интерфейс исходящего multicast по умолчанию или возвращает выбор системе. multicastInterface должен быть корректной строковой записью IP из семейства сокета.
Для IPv4 это обычно IP нужного физического интерфейса. Все multicast-пакеты с этого сокета идут через интерфейс, заданный последним успешным вызовом.
Для IPv6 в multicastInterface нужна область (scope), как в примерах ниже. Отдельные вызовы send могут указывать scope в адресе; на последний успешный вызов влияют только пакеты к multicast без явной области.
На несвязанном сокете метод выбрасывает EBADF.
Пример: исходящий multicast-интерфейс IPv6¶
В большинстве систем формат scope — имя интерфейса:
1 2 3 4 5 | |
В Windows в формате scope используется номер интерфейса:
1 2 3 4 5 | |
Пример: исходящий multicast-интерфейс IPv4¶
На всех системах — IP хоста на нужном физическом интерфейсе:
1 2 3 4 5 | |
Результат вызова¶
Вызов на сокете, не готовом к отправке или уже закрытом, может выбросить ошибку Not running Error.
Если multicastInterface нельзя разобрать как IP, выбрасывается EINVAL системная ошибка.
В IPv4 при корректном, но не совпадающем с интерфейсом адресе или несовпадении семейства — системная ошибка, например EADDRNOTAVAIL или EPROTONOSUP.
В IPv6 при ошибках указания или пропуска scope сокет часто продолжает использовать выбор интерфейса по умолчанию.
Адрес ANY семейства сокета (IPv4 '0.0.0.0' или IPv6 '::') можно использовать, чтобы вернуть выбор исходящего интерфейса для multicast системе.
socket.setMulticastLoopback(flag)¶
flag<boolean>
Устанавливает или сбрасывает опцию IP_MULTICAST_LOOP. При true multicast-пакеты также принимаются на локальном интерфейсе.
На несвязанном сокете метод выбрасывает EBADF.
socket.setMulticastTTL(ttl)¶
ttl<integer>
Задаёт опцию IP_MULTICAST_TTL. Хотя TTL обычно расшифровывают как «Time to Live», здесь это число IP-прыжков для multicast-трафика. Каждый маршрутизатор уменьшает TTL; при достижении 0 пакет не пересылается.
Аргумент ttl от 0 до 255. На большинстве систем по умолчанию 1.
На несвязанном сокете метод выбрасывает EBADF.
socket.setRecvBufferSize(size)¶
size<integer>
Задаёт опцию SO_RCVBUF — максимальный буфер приёма сокета в байтах.
На несвязанном сокете метод выбрасывает ERR_SOCKET_BUFFER_SIZE.
socket.setSendBufferSize(size)¶
size<integer>
Задаёт опцию SO_SNDBUF — максимальный буфер отправки сокета в байтах.
На несвязанном сокете метод выбрасывает ERR_SOCKET_BUFFER_SIZE.
socket.setTTL(ttl)¶
ttl<integer>
Задаёт опцию IP_TTL. Здесь это число IP-прыжков для пакета; маршрутизаторы уменьшают TTL; при 0 пакет не пересылается. Изменение TTL обычно используют для зондов или multicast.
Аргумент ttl от 1 до 255. На большинстве систем по умолчанию 64.
На несвязанном сокете метод выбрасывает EBADF.
socket.unref()¶
- Возвращает:
<dgram.Socket>
По умолчанию привязка сокета удерживает процесс Node.js от завершения, пока сокет открыт. socket.unref() исключает сокет из подсчёта ссылок, и процесс может завершиться, даже если сокет ещё слушает.
Повторные вызовы socket.unref() не дают дополнительного эффекта.
socket.unref() возвращает ссылку на сокет для цепочки вызовов.
Функции модуля node:dgram¶
dgram.createSocket(options[, callback])¶
Добавлено в: v0.11.13
options<Object>Доступные опции:type<string>Семейство сокета:'udp4'или'udp6'. Обязательно.reuseAddr<boolean>Приtruesocket.bind()переиспользует адрес, даже если другой процесс уже привязал сокет, но данные получит только один сокет. По умолчанию:false.reusePort<boolean>Приtruesocket.bind()переиспользует порт, даже если другой процесс уже привязал сокет. Входящие датаграммы распределяются между слушающими сокетами. Опция доступна только на части платформ: Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, AIX 7.2.5+. На неподдерживаемых платформах при привязке возникает ошибка. По умолчанию:false.ipv6Only<boolean>Приipv6Only: trueотключается dual-stack, т.е. привязка к::не привязывает0.0.0.0. По умолчанию:false.recvBufferSize<number>ЗначениеSO_RCVBUF.sendBufferSize<number>ЗначениеSO_SNDBUF.lookup<Function>Пользовательская функция поиска. По умолчанию:dns.lookup().signal<AbortSignal>Сигнал для закрытия сокета.receiveBlockList<net.BlockList>Отбрасывает входящие датаграммы с заданных IP, диапазонов или подсетей. Не работает за обратным прокси, NAT и т.п.: проверяется адрес прокси или NAT, а не клиента.sendBlockList<net.BlockList>Блокирует исходящую отправку на заданные IP, диапазоны или подсети.
callback<Function>Обработчик событий'message'. Необязательно.- Возвращает:
<dgram.Socket>
Создаёт объект dgram.Socket. После создания вызов socket.bind() запускает приём датаграмм. Если в socket.bind() не переданы address и port, сокет привязывается к адресу «все интерфейсы» на случайном порту (корректно для udp4 и udp6). Привязанный адрес и порт можно получить через socket.address().address и socket.address().port.
Если задана опция signal, вызов .abort() у соответствующего AbortController аналогичен .close() у сокета:
1 2 3 4 5 6 7 8 9 10 | |
dgram.createSocket(type[, callback])¶
type<string>'udp4'или'udp6'.callback<Function>Обработчик событий'message'.- Возвращает:
<dgram.Socket>
Создаёт dgram.Socket указанного type.
После создания socket.bind() запускает приём датаграмм. Без address и port в socket.bind() сокет привязывается к «все интерфейсы» на случайном порту (для udp4 и udp6). Адрес и порт — socket.address().address и socket.address().port.
