UDP/сокеты дейтаграмм
Исходный код: lib/dgram.js
Модуль dgram предоставляет реализацию сокетов UDP дейтаграмм.
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
});
server.bind(41234);
// Prints: server listening 0.0.0.0:41234 Класс: dgram.Socket
- Расширяет: <EventEmitter>
Оборачивает функциональность дейтаграмм.
Новые экземпляры dgram.Socket создаются с помощью dgram.createSocket(). Ключевое слово new не должно использоваться для создания экземпляров dgram.Socket.
Событие: 'close'
Событие 'close' генерируется после закрытия сокета с помощью close(). После срабатывания новые события 'message' на этом сокете больше не будут генерироваться.
Событие: 'connect'
Событие 'connect' генерируется после ассоциации сокета с удаленным адресом в результате успешного вызова connect().
Событие: 'error'
-
exception<Ошибка>
Событие 'error' генерируется всякий раз, когда возникает ошибка. Функция-обработчик события получает в качестве единственного аргумента объект Error.
Событие: 'listening'
Событие 'listening' генерируется, как только сокет dgram.Socket готов к приёму данных. Это происходит либо явно с помощью socket.bind(), либо неявно при первом отправлении данных с помощью socket.send(). Пока сокет dgram.Socket не находится в режиме ожидания, системные ресурсы для него не существуют, и вызовы типа socket.address() и socket.setTTL() завершатся ошибкой.
Событие: 'message'
Событие 'message' генерируется, когда на сокете становится доступна новая дейтаграмма. Функция-обработчик события получает два аргумента: msg и rinfo.
Если исходный адрес входящего пакета — локальный IPv6-адрес, имя интерфейса добавляется к address. Например, пакет, полученный на интерфейсе en0, может иметь поле адреса 'fe80::2618:1234:ab11:3b9c%en0', где '%en0' — имя интерфейса в качестве суффикса идентификатора зоны.
socket.addMembership(multicastAddress[, multicastInterface])
Уведомляет ядро о присоединении к группе multicast по заданному multicastAddress и multicastInterface с использованием опции сокета IP_ADD_MEMBERSHIP. Если аргумент multicastInterface не указан, операционная система выберет один интерфейс и присоединит к нему членство. Для добавления членства ко всем доступным интерфейсам необходимо вызвать addMembership несколько раз, по одному разу для каждого интерфейса.
При вызове на незакреплённом сокете этот метод неявно привяжет его к произвольному порту, прослушивая все интерфейсы.
При совместном использовании сокета UDP между несколькими рабочими процессами cluster функция socket.addMembership() должна быть вызвана только один раз, иначе возникнет ошибка EADDRINUSE.
const cluster = require('cluster');
const dgram = require('dgram');
if (cluster.isMaster) {
cluster.fork(); // Works ok.
cluster.fork(); // Fails with EADDRINUSE.
} else {
const s = dgram.createSocket('udp4');
s.bind(1234, () => {
s.addMembership('224.0.0.114');
});
} socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
Уведомляет ядро о присоединении к источнику-специфичному multicast-каналу по заданному sourceAddress и groupAddress, используя опцию сокета multicastInterface с IP_ADD_SOURCE_MEMBERSHIP socket option. Если аргумент multicastInterface не указан, операционная система выберет один интерфейс и присоединит к нему членство. Для добавления членства ко всем доступным интерфейсам необходимо вызвать socket.addSourceSpecificMembership() несколько раз, по одному разу для каждого интерфейса.
При вызове на незакреплённом сокете этот метод неявно привяжет его к произвольному порту, прослушивая все интерфейсы.
socket.address()
- Возвращает: <Объект>
Возвращает объект, содержащий информацию об адресе сокета. Для сокетов UDP этот объект будет содержать свойства address, family и port.
Этот метод генерирует EBADF, если вызывается на незакрепленном сокете.
socket.bind([port][, address][, callback])
-
port<целое число> -
address<строка> -
callback<Функция> без параметров. Вызывается по завершении привязки.
Для сокетов UDP, вызывает dgram.Socket для прослушивания сообщений дейтаграмм по указанному port и, опционально, address. Если port не указано или равно 0, операционная система попытается привязаться к произвольному порту. Если address не указано, операционная система попытается прослушать все адреса. После завершения привязки, генерируется событие 'listening' и, опционально, вызывается функция callback.
Одновременное указание обработчика события 'listening' и передача callback методу socket.bind() не вредно, но не очень полезно.
Привязанный сокет дейтаграмм сохраняет процесс Node.js запущенным для получения сообщений дейтаграмм.
Если привязка завершается ошибкой, генерируется событие 'error'. В редких случаях (например, при попытке привязать закрытый сокет) может быть выброшена ошибка Error.
Пример UDP сервера, прослушивающего порт 41234:
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
});
server.bind(41234);
// Prints: server listening 0.0.0.0:41234 socket.bind(options[, callback])
-
options<Объект> Требуется. Поддерживает следующие свойства:-
port<целое число> -
address<строка> -
exclusive<логическое значение> -
fd<целое число>
-
-
callback<Функция>
Для сокетов UDP вызывает dgram.Socket для прослушивания сообщений дейтаграмм по указанному port и, опционально, address, переданным в виде свойств объекта options в качестве первого аргумента. Если port не указано или равно 0, операционная система попытается привязаться к произвольному порту. Если address не указано, операционная система попытается прослушать все адреса. После завершения привязки, генерируется событие 'listening' и, опционально, вызывается функция callback.
Объект options может содержать свойство fd. Если значение fd больше, чем 0, будет использоваться существующий сокет с заданным дескриптором файла. В этом случае свойства port и address будут проигнорированы.
Одновременное указание обработчика события 'listening' и передача callback методу socket.bind() не вредно, но не очень полезно.
Объект options может содержать дополнительное свойство exclusive, используемое при работе с объектами dgram.Socket с модулем cluster. Когда exclusive установлено в false (по умолчанию), рабочие процессы кластера будут использовать один и тот же системный дескриптор сокета, что позволит совместно обрабатывать подключения. Однако, когда exclusive равно true, дескриптор не будет совместно использоваться, и попытка совместного использования порта приведёт к ошибке.
Привязанный сокет дейтаграммы удерживает процесс Node.js работающим для получения сообщений дейтаграммы.
Если привязка завершается неудачно, генерируется событие 'error'. В редких случаях (например, при попытке привязать закрытый сокет) может быть брошено исключение Error.
Ниже показан пример сокета, прослушивающего эксклюзивный порт.
socket.bind({
address: 'localhost',
port: 8000,
exclusive: true
}); socket.close([callback])
-
callback<Функция> Вызывается, когда сокет закрыт.
Закройте базовый сокет и прекратите прослушивание данных на нём. Если указан обратный вызов, он добавляется в качестве слушателя события 'close'.
socket.connect(port[, address][, callback])
Устанавливает связь 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])
Инструктирует ядро покинуть мультивещательную группу в multicastAddress с помощью параметра сокета IP_DROP_MEMBERSHIP. Этот метод автоматически вызывается ядром при закрытии сокета или завершении процесса, поэтому большинство приложений никогда не будут вызывать его.
Если multicastInterface не указан, операционная система попытается выйти из группы на всех допустимых интерфейсах.
socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
Инструктирует ядро покинуть мультивещательный канал с указанным sourceAddress и groupAddress с использованием параметра сокета IP_DROP_SOURCE_MEMBERSHIP. Этот метод автоматически вызывается ядром при закрытии сокета или завершении процесса, поэтому большинство приложений никогда не будут вызывать его.
Если multicastInterface не указан, операционная система попытается выйти из группы на всех допустимых интерфейсах.
socket.getRecvBufferSize()
- Возвращает: <число> размер буфера приема сокета
SO_RCVBUFв байтах.
Этот метод генерирует исключение ERR_SOCKET_BUFFER_SIZE, если он вызывается для неинициализированного сокета.
socket.getSendBufferSize()
- Возвращает: <число> размер буфера отправки сокета
SO_SNDBUFв байтах.
Этот метод генерирует исключение ERR_SOCKET_BUFFER_SIZE, если он вызывается для неинициализированного сокета.
socket.ref()
- Возвращает: <dgram.Сокет>
По умолчанию привязка сокета блокирует выход процесса Node.js, пока сокет открыт. Метод socket.unref() можно использовать для исключения сокета из подсчёта ссылок, удерживающего активный процесс Node.js. Метод socket.ref() добавляет сокет обратно в счётчик ссылок и восстанавливает поведение по умолчанию.
Вызов socket.ref() несколько раз не повлияет дополнительно.
Метод socket.ref() возвращает ссылку на сокет, чтобы вызовы могли быть объединены.
socket.remoteAddress()
- Возвращает: <Объект>
Возвращает объект, содержащий address, family, и port удалённого узла. Этот метод генерирует исключение ERR_SOCKET_DGRAM_NOT_CONNECTED, если сокет не подключён.
socket.send(msg[, offset, length][, port][, address][, callback])
-
msg<Буфер> | <Массив типов> | <DataView> | <строка> | <Массив> Отправляемое сообщение. -
offset<целое> Смещение в буфере, где начинается сообщение. -
length<целое> Количество байтов в сообщении. -
port<целое> Порт назначения. -
address<строка> Имя хоста или IP-адрес назначения. -
callback<Функция> Вызывается при отправке сообщения.
Отправляет дейтаграмму по сокету. Для беспроводных сокетов необходимо указать port и address. Подключённые сокеты, с другой стороны, будут использовать связанный удалённый узел, поэтому аргументы port и address не должны быть установлены.
Аргумент msg содержит отправляемое сообщение. В зависимости от его типа, может применяться разное поведение. Если msg является Buffer, любым TypedArray или DataView, offset и length указывают смещение в Buffer, где начинается сообщение, и количество байтов в сообщении соответственно. Если msg является String, он автоматически преобразуется в Buffer с кодировкой 'utf8'.
Если msg — массив, offset и length не должны быть указаны.
Аргумент address — это строка. Если значение address — имя хоста, для разрешения адреса хоста будет использоваться DNS. Если address не указан или имеет ложное значение, по умолчанию будет использоваться '127.0.0.1' (для сокетов udp4 ) или '::1' (для сокетов udp6 ).
Если сокет не был ранее привязан с помощью вызова bind, сокету назначается случайный номер порта, и он привязывается к адресу "все интерфейсы" ('0.0.0.0' для сокетов udp4 , '::0' для сокетов udp6).
Необязательная функция callback может быть указана для сообщения об ошибках DNS или для определения того, когда безопасно повторно использовать объект buf. Поиск по DNS задерживает время отправки по меньшей мере на один тик цикла событий Node.js.
Единственный способ точно узнать, что датаграмма была отправлена, — использовать callback. Если произошла ошибка и был передан callback, ошибка будет передана в качестве первого аргумента в callback. Если callback не задан, ошибка будет выведена как событие 'error' объекта socket.
Смещение и длина являются необязательными, но оба обязательно должны быть установлены, если они используются. Они поддерживаются только в том случае, если первый аргумент — это Buffer, TypedArray или DataView.
Этот метод вызывает ERR_SOCKET_BAD_PORT, если он вызван на несвязанном сокете.
Пример отправки UDP-пакета на порт на localhost;
const dgram = require('dgram');
const message = Buffer.from('Some bytes');
const client = dgram.createSocket('udp4');
client.send(message, 41234, 'localhost', (err) => {
client.close();
}); Пример отправки UDP-пакета, состоящего из нескольких буферов, на порт на 127.0.0.1;
const dgram = require('dgram');
const buf1 = Buffer.from('Some ');
const buf2 = Buffer.from('bytes');
const client = dgram.createSocket('udp4');
client.send([buf1, buf2], 41234, (err) => {
client.close();
}); Отправка нескольких буферов может быть быстрее или медленнее в зависимости от приложения и операционной системы. Выполняйте бенчмаркинг, чтобы определить оптимальную стратегию в каждом конкретном случае. Однако, как правило, отправка нескольких буферов быстрее.
Пример отправки UDP-пакета с использованием сокета, подключенного к порту на localhost;
const dgram = require('dgram');
const message = Buffer.from('Some bytes');
const client = dgram.createSocket('udp4');
client.connect(41234, 'localhost', (err) => {
client.send(message, (err) => {
client.close();
});
}); Примечание о размере UDP-датаграммы
Максимальный размер IPv4/v6-датаграммы зависит от MTU (Максимальной единицы передачи) и размера поля Payload Length.
-
Поле
Payload Lengthимеет ширину 16 бит, что означает, что обычный полезный груз не может превышать 64К байт, включая заголовок интернета и данные (65 507 байт = 65 535 − 8 байт заголовка UDP − 20 байт заголовка IP); это, как правило, верно для петель обратной связи, но такие длинные сообщения датаграмм непрактичны для большинства хостов и сетей. -
MTU— это максимальный размер, который может поддерживать заданная технология канального уровня для сообщений датаграмм. Для любой связи IPv4 предписывает минимальныйMTUв 68 октетов, а рекомендуемыйMTUдля IPv4 — 576 (обычно рекомендуется какMTUдля приложений типа dial-up), независимо от того, поступают ли они целиком или фрагментированно.Для IPv6 минимальный
MTUсоставляет 1280 октетов. Однако обязательный минимальный размер буфера для сборки фрагментов составляет 1500 октетов. Значение 68 октетов очень мало, так как большинство современных технологий канального уровня, таких как Ethernet, имеют минимальныйMTU1500.
Невозможно заранее узнать MTU каждого канала, через который может пройти пакет. Отправка датаграммы больше, чем MTU получателя, не сработает, потому что пакет будет молча отброшен без уведомления источника о том, что данные не достигли адресата.
socket.setBroadcast(flag)
Устанавливает или сбрасывает параметр сокета SO_BROADCAST. Если установлено true, UDP-пакеты могут отправляться на адрес локального широковещания интерфейса.
Этот метод вызывает EBADF при вызове на несвязанном сокете.
socket.setMulticastInterface(multicastInterface)
-
multicastInterface<строка>
Все ссылки на область действия в этом разделе относятся к Индексам зон адресов IPv6, которые определены в RFC 4007. В строковом формате IP с индексом области действия записывается как 'IP%scope', где scope — это имя интерфейса или номер интерфейса.
Устанавливает интерфейс по умолчанию для исходящего мультивещания сокета на выбранный интерфейс или возвращает его к выбору системного интерфейса. multicastInterface должен быть допустимой строковой записью IP-адреса из семейства сокета.
Для сокетов IPv4 это должен быть IP-адрес, настроенный для нужного физического интерфейса. Все пакеты, отправленные на мультивещание по сокету, будут отправлены по интерфейсу, определяемому последним успешным использованием этого вызова.
Для сокетов IPv6 multicastInterface должен включать область действия, чтобы указать интерфейс, как показано в следующих примерах. В IPv6 отдельные send вызовы также могут использовать явный область действия в адресах, поэтому только пакеты, отправленные на адрес мультивещания без явного указания области действия, зависят от последнего успешного использования этого вызова.
Этот метод вызывает EBADF при вызове на несвязанном сокете.
Пример: IPv6 исходящий интерфейс мультивещания
На большинстве систем, где формат области действия использует имя интерфейса:
const socket = dgram.createSocket('udp6');
socket.bind(1234, () => {
socket.setMulticastInterface('::%eth1');
}); В Windows, где формат области действия использует номер интерфейса:
const socket = dgram.createSocket('udp6');
socket.bind(1234, () => {
socket.setMulticastInterface('::%2');
}); Пример: IPv4 исходящий интерфейс мультивещания
Все системы используют IP-адрес хоста на нужном физическом интерфейсе:
const socket = dgram.createSocket('udp4');
socket.bind(1234, () => {
socket.setMulticastInterface('10.0.0.2');
}); Результаты вызова
Вызов на сокете, который не готов к отправке или больше не открыт, может вызвать ошибку Не работает Error.
Если multicastInterface не может быть проанализирован как IP-адрес, возникает ошибка EINVAL System Error.
В IPv4, если multicastInterface — это допустимый адрес, но он не соответствует ни одному интерфейсу, или если адрес не соответствует семейству, возникает ошибка System Error, такая как EADDRNOTAVAIL или EPROTONOSUP.
В IPv6 большинство ошибок с указанием или пропуском области действия приведут к тому, что сокет продолжит использовать (или вернётся к) выбору системного интерфейса по умолчанию.
Любой адрес семейства адресов сокета (IPv4 '0.0.0.0' или IPv6 '::') может использоваться для возвращения управления сокета к системному выбору исходящего интерфейса по умолчанию для будущих пакетов мультивещания.
socket.setMulticastLoopback(flag)
Устанавливает или сбрасывает параметр сокета IP_MULTICAST_LOOP. При установке в значение true пакеты мультивещания также будут приниматься на локальном интерфейсе.
Этот метод вызывает EBADF при вызове на несвязанном сокете.
socket.setMulticastTTL(ttl)
-
ttl<целое число>
Устанавливает параметр сокета IP_MULTICAST_TTL. Хотя TTL обычно означает «время жизни», в этом контексте он определяет количество IP-прыжков, которые пакету разрешается пройти, в частности, для трафика мультивещания. Каждый маршрутизатор или шлюз, передающий пакет, уменьшает TTL. Если маршрутизатор уменьшит TTL до 0, пакет не будет перенаправлен.
Аргумент ttl может быть от 0 до 255. Значение по умолчанию на большинстве систем — 1.
Этот метод вызывает EBADF при вызове на несвязанном сокете.
socket.setRecvBufferSize(size)
-
size<целое число>
Устанавливает параметр сокета SO_RCVBUF. Устанавливает максимальный буфер приема сокета в байтах.
Этот метод вызывает ERR_SOCKET_BUFFER_SIZE, если он вызван на несвязанном сокете.
socket.setSendBufferSize(size)
-
size<целое число>
Устанавливает параметр сокета SO_SNDBUF. Устанавливает максимальный буфер отправки сокета в байтах.
Этот метод вызывает ERR_SOCKET_BUFFER_SIZE, если он вызван на несвязанном сокете.
socket.setTTL(ttl)
-
ttl<целое число>
Устанавливает параметр сокета IP_TTL. Хотя TTL обычно означает «время жизни», в этом контексте он определяет количество IP-прыжков, которые пакету разрешается пройти. Каждый маршрутизатор или шлюз, передающий пакет, уменьшает TTL. Если маршрутизатор уменьшит TTL до 0, пакет не будет перенаправлен. Изменение значений TTL обычно выполняется для зондирования сети или при использовании мультивещания.
Аргумент ttl может принимать значения от 1 до 255. Значение по умолчанию на большинстве систем — 64.
Этот метод вызывает EBADF при вызове на несвязанном сокете.
socket.unref()
- Возвращает: <dgram.Сокет>
По умолчанию привязка сокета заблокирует выход процесса Node.js, пока сокет открыт. Метод socket.unref() может быть использован, чтобы исключить сокет из подсчета ссылок, который удерживает процесс Node.js активным, позволяя процессу выйти, даже если сокет всё ещё прослушивает.
Вызов socket.unref() несколько раз не приведёт к дополнительным эффектам.
Метод socket.unref() возвращает ссылку на сокет, что позволяет цепочку вызовов.
dgram функции модуля
dgram.createSocket(options[, callback])
-
options<Объект> Доступные параметры:-
type<строка> Семейство сокета. Должно быть либо'udp4', либо'udp6'. Обязательно. -
reuseAddr<логическое значение> Еслиtruesocket.bind()будет повторно использовать адрес, даже если другой процесс уже привязал сокет к нему. По умолчанию:false. -
ipv6Only<логическое значение> Установкаipv6Onlyвtrueотключит поддержку двойного стека, т.е. привязка к адресу::не приведет к привязке0.0.0.0. По умолчанию:false. -
recvBufferSize<число> Устанавливает значение сокетаSO_RCVBUF. -
sendBufferSize<число> Устанавливает значение сокетаSO_SNDBUF. -
lookup<Функция> Пользовательская функция поиска. По умолчанию:dns.lookup().
-
-
callback<Функция> Прикрепляется в качестве обработчика событий'message'. Необязательно. - Возвращает: <dgram.Сокет>
Создаёт объект dgram.Socket. После создания сокета, вызов socket.bind() указывает сокету начать прослушивание сообщений дейтаграмм. Когда address и port не переданы в socket.bind(), метод привяжет сокет к адресу "все интерфейсы" на случайном порту (он делает правильные вещи как для сокетов udp4 , так и для udp6 ). Связанный адрес и порт можно получить с помощью socket.address().address и socket.address().port.
dgram.createSocket(type[, callback])
-
type<строка> Либо'udp4', либо'udp6'. -
callback<Функция> Прикрепляется в качестве обработчика событий'message'. - Возвращает: <dgram.Сокет>
Создаёт объект dgram.Socket указанного типа type.
После создания сокета, вызов socket.bind() указывает сокету начать прослушивание сообщений дейтаграмм. Когда address и port не переданы в socket.bind(), метод привяжет сокет к адресу "все интерфейсы" на случайном порту (он делает правильные вещи как для сокетов udp4 , так и для udp6 ). Связанный адрес и порт можно получить с помощью socket.address().address и socket.address().port.
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v12.x/docs/api/dgram.html