UDP/Датagram-сокеты
Модуль 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);
// server listening 0.0.0.0:41234
Класс: dgram.Socket
Объект dgram.Socket является объектом EventEmitter, который инкапсулирует функциональность дейтаграмм.
Новые экземпляры dgram.Socket создаются с помощью dgram.createSocket(). Ключевое слово new не используется для создания экземпляров dgram.Socket.
Событие: 'close'
Событие 'close' генерируется после закрытия сокета с помощью close(). После его срабатывания новые события 'message' на этом сокете не будут генерироваться.
Событие: 'error'
-
exception<Ошибка>
Событие 'error' генерируется всякий раз, когда происходит ошибка. Обработчик событий получает один объект Error.
Событие: 'listening'
Событие 'listening' генерируется всякий раз, когда сокет начинает прослушивать сообщения дейтаграмм. Это происходит сразу после создания UDP-сокетов.
Событие: 'message'
Событие 'message' генерируется, когда на сокете появляется новое сообщение дейтаграммы. Обработчик событий получает два аргумента: msg и rinfo.
socket.addMembership(multicastAddress[, multicastInterface])
Указывает ядру присоединиться к группе мультивещания по заданному 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.address()
Возвращает объект, содержащий информацию об адресе сокета. Для UDP-сокетов этот объект будет содержать address, family и port свойства.
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);
// server listening 0.0.0.0:41234
socket.bind(options[, callback])
-
options<Объект> Требуется. Поддерживает следующие свойства:-
port<Целое число> -
address<Строка> -
exclusive<Булево>
-
-
callback<Функция>
Для UDP-сокетов заставляет dgram.Socket прослушивать сообщения дейтаграмм по указанному port и необязательному address , которые передаются как свойства объекта options в качестве первого аргумента. Если port не указан или равен 0, операционная система попытается привязаться к случайному порту. Если address не указан, операционная система попытается прослушивать все адреса. После завершения привязки генерируется событие 'listening' и, если задана, вызывается функция callback.
Обратите внимание, что указание слушателя события '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])
Закрыть базовый сокет и прекратить прослушивание данных на нём. Если указан обработчик, он добавляется как слушатель события 'close'.
socket.dropMembership(multicastAddress[, multicastInterface])
Инструктирует ядро покинуть группу мультивещания по multicastAddress используя опцию сокета IP_DROP_MEMBERSHIP. Этот метод автоматически вызывается ядром при закрытии сокета или завершении процесса, поэтому большинству приложений никогда не придётся его вызывать.
Если multicastInterface не указан, операционная система попытается покинуть членство на всех доступных интерфейсах.
socket.getRecvBufferSize()
- Возвращает: <Число> размер буфера приема сокета в байтах.
socket.getSendBufferSize()
- Возвращает: <Число> размер буфера отправки сокета в байтах.
socket.ref()
По умолчанию, привязка сокета приводит к блокировке процесса Node.js до тех пор, пока сокет открыт. Метод socket.unref() может быть использован для исключения сокета из подсчёта ссылок, который удерживает активным процесс Node.js. Метод socket.ref() добавляет сокет обратно в подсчёт ссылок и восстанавливает стандартное поведение.
Вызов socket.ref() несколько раз не приведёт к дополнительным эффектам.
Метод socket.ref() возвращает ссылку на сокет, позволяя выполнять цепочку вызовов.
socket.send(msg, [offset, length,] port [, address] [, callback])
-
msg<Buffer> | <Uint8Array> | <строка> | <массив> Сообщение для отправки. -
offset<число> Целое число. Смещение в буфере, где начинается сообщение. -
length<число> Целое число. Количество байтов в сообщении. -
port<число> Целое число. Порт назначения. -
address<строка> Имя хоста или IP-адрес назначения. -
callback<функция> Вызывается при отправке сообщения.
Отправляет дейтаграмму по сокету. Необходимо указать адрес и порт назначения port и address.
Аргумент msg содержит сообщение для отправки. В зависимости от его типа, может применяться разное поведение. Если msg является Buffer или Uint8Array, параметры offset и length определяют смещение в Buffer и количество байтов в сообщении соответственно. Если msg является String, оно автоматически преобразуется в Buffer с кодировкой 'utf8'. При сообщениях, содержащих многобайтовые символы, offset и length вычисляются относительно длины в байтах, а не позиции символа. Если 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 или Uint8Array.
Пример отправки 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-дейтаграммы
Максимальный размер UDP-дейтаграммы зависит от MTU (Максимального размера блока передачи) и от размера поля Payload Length.
-
Поле
Payload Lengthимеет ширину16 bits, что означает, что обычная нагрузка превысит 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, имеют минимальныйMTUиз1500.
Невозможно заранее знать MTU каждого канала, по которому может проходить пакет. Отправка дейтаграммы, превышающей размер буфера получателя MTU, не сработает, поскольку пакет будет молча отброшен без уведомления источника о том, что данные не достигли адресата.
socket.setBroadcast(flag)
Устанавливает или сбрасывает параметр сокета SO_BROADCAST. При установке в true UDP-пакеты могут отправляться на адрес широковещательной рассылки локального интерфейса.
socket.setMulticastInterface(multicastInterface)
-
multicastInterface<строка>
Примечание: Все ссылки на область действия в этом разделе относятся к индексам зоны IPv6, которые определены в RFC 4007. В строчном формате IP с индексом области действия записывается как 'IP%scope' где область действия — имя или номер интерфейса.
Устанавливает значение по умолчанию исходящего интерфейса для мультиадресной рассылки сокета на выбранный интерфейс или на выбор системного интерфейса. multicastInterface должен быть корректной строковой записью IP-адреса из семейства сокета.
Для IPv4-сокетов это должен быть IP-адрес, настроенный для нужного физического интерфейса. Все пакеты, отправляемые в мультиадресную рассылку по сокету, будут отправляться по интерфейсу, определенному последним успешным использованием этого вызова.
Для IPv6-сокетов multicastInterface должен содержать область действия, чтобы указать интерфейс, как в примерах ниже. В IPv6 отдельные send вызовы также могут использовать явный индекс области в адресах, поэтому только пакеты, отправленные на мультиадресной адрес без явного указания области, влияют на последнее успешное использование этого вызова.
Примеры: 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 большинство ошибок при указании или пропуске области действия приведут к тому, что сокет будет продолжать использовать (или возвращаться к) выбору системного интерфейса по умолчанию.
Адрес ANY семейства адресов сокета (IPv4 '0.0.0.0' или IPv6 '::') может использоваться для возврата управления по умолчанию исходящим интерфейсом сокетов системе для будущих пакетов мультиадресной рассылки.
socket.setMulticastLoopback(flag)
-
flag<boolean>
Устанавливает или очищает параметр сокета IP_MULTICAST_LOOP. Если установлен в true, пакеты multicast также будут приниматься на локальном интерфейсе.
socket.setMulticastTTL(ttl)
-
ttl<number> Целое число.
Устанавливает параметр сокета IP_MULTICAST_TTL. Хотя TTL обычно означает «Время жизни», в данном контексте он определяет количество IP-пересадок, которые пакет разрешено пройти, в частности, для мультимедийного трафика. Каждый маршрутизатор или шлюз, пересылающий пакет, уменьшает TTL. Если TTL уменьшается до 0 маршрутизатором, пакет не будет пересылаться.
Передаваемое аргумент в socket.setMulticastTTL() число пересадок от 0 до 255. По умолчанию на большинстве систем 1, но может отличаться.
socket.setRecvBufferSize(size)
-
size<number> Целое число
Устанавливает параметр сокета SO_RCVBUF. Устанавливает максимальный буфер приема сокета в байтах.
socket.setSendBufferSize(size)
-
size<number> Целое число
Устанавливает параметр сокета SO_SNDBUF. Устанавливает максимальный буфер отправки сокета в байтах.
socket.setTTL(ttl)
-
ttl<number> Целое число.
Устанавливает параметр сокета IP_TTL. Хотя TTL обычно означает «Время жизни», в данном контексте он определяет количество IP-пересадок, которые пакет разрешено пройти. Каждый маршрутизатор или шлюз, пересылающий пакет, уменьшает TTL. Если TTL уменьшается до 0 маршрутизатором, пакет не будет пересылаться. Изменение значений TTL обычно выполняется для сетевых зондирований или при мультивещании.
Аргумент для socket.setTTL() — число пересадок от 1 до 255. По умолчанию на большинстве систем 64, но может отличаться.
socket.unref()
По умолчанию привязка сокета заблокирует процесс Node.js до тех пор, пока сокет не будет закрыт. Метод socket.unref() может использоваться для исключения сокета из подсчета ссылок, который поддерживает активность процесса Node.js, позволяя процессу выйти, даже если сокет всё ещё прослушивает.
Вызов socket.unref() несколько раз не повлияет.
Метод socket.unref() возвращает ссылку на сокет, поэтому вызовы могут быть объединены.
Изменение асинхронного socket.bind() поведения
Начиная с Node.js v0.10, dgram.Socket#bind() изменился на асинхронную модель выполнения. Код старого образца, предполагающий синхронное поведение, как в приведённом примере:
const s = dgram.createSocket('udp4');
s.bind(1234);
s.addMembership('224.0.0.114');
Должен быть изменён, чтобы передать функцию обратного вызова в dgram.Socket#bind() функцию:
const s = dgram.createSocket('udp4');
s.bind(1234, () => {
s.addMembership('224.0.0.114');
});
dgram функции модуля
dgram.createSocket(options[, callback])
-
options<Object> Доступные параметры:-
type<string> Семейство сокета. Должно быть либо'udp4'или'udp6'. Требуется. -
reuseAddr<boolean> Когдаtruesocket.bind()будет повторно использовать адрес, даже если другой процесс уже привязал сокет к нему. По умолчанию:false. -
recvBufferSize<number> - Устанавливает значение сокетаSO_RCVBUF. -
sendBufferSize<number> - Устанавливает значение сокетаSO_SNDBUF. -
lookup<Function> Пользовательская функция поиска. По умолчанию:dns.lookup().
-
-
callback<Function> Прикреплён как обработчик событий'message'. Необязательно. - Возвращает: <dgram.Socket>
Создаёт объект dgram.Socket. После создания сокета, вызов socket.bind() укажет сокету начать прослушивание сообщений датаграмм. Когда address и port не передаются в socket.bind(), метод привяжет сокет к адресу «всех интерфейсов» на случайном порту (он выполняет правильную работу как для udp4 так и для udp6 сокетов). Связанный адрес и порт можно получить с помощью socket.address().address и socket.address().port.
dgram.createSocket(type[, callback])
-
type<string> - Либо 'udp4', либо 'udp6'. -
callback<Function> - Прикреплён как обработчик событий'message'. - Возвращает: <dgram.Socket>
Создаёт объект dgram.Socket указанного типа type. Аргумент type может быть либо udp4 или udp6. Необязательная функция callback может быть передана, которая добавляется как обработчик событий 'message'.
После создания сокета, вызов 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-v8.x/docs/api/dgram.html