mDNS это широковещательная служба (multicast UDP), которая используется для предоставления локально сетевой службы распознавания имен хоста.
mDNS устанавливается по умолчанию на большинстве операционных систем, или её библиотека доступна как отдельный пакет. На Mac OS она устанавливается по умолчанию, и называется Bonjour. Apple выпустила инсталлятор для Windows, который можно найти на страничке поддержки Apple. На Linux mDNS предоставляется avahi, и обычно устанавливается по умолчанию.
[Свойства mDNS]
hostname: имя устройства, которое будет оно будет отвечать. Если оно не установлено, то hostname будет прочитано из интерфейса. Пример: имя my-esp32 будет разрешаться в my-esp32.local.
default_instance: дружественное имя для вашего устройства, наподобие Jhon's ESP32 Thing. Если не установлено, то будет использоваться hostname.
Пример запуска mDNS для интерфейса STA, и установка hostname и default_instance:
void start_mdns_service()
{
// Инициализация службы mDNS:
esp_err_t err = mdns_init();
if (err) {
printf("MDNS Init failed: %d\n", err);
return;
}
// Установка hostname:
mdns_hostname_set("my-esp32");
// Установка default instance:
mdns_instance_name_set("Jhon's ESP32 Thing");
}
[Службы mDNS]
mDNS может предоставлять информацию о сетевых службах, которые предоставляет ваше устройство. Каждая служба определяется несколькими свойствами.
instance_name: дружественное имя для службы, наподобие Jhon's ESP32 Web Server. Если не определено, то будет использоваться default_instance.
service_type: (необходимое свойство) тип службы, добавленное с символом нижнего подчеркивания. Некоторые общие типы можно найти в [2].
proto: (необходимое свойство) протокол, на котором работает служба, символом нижнего подчеркивания. Пример: _tcp или _udp.
port: (необходимое свойство) сетевой порт, через который работает служба.
txt: {var, val} массив строк, используемый для определения вашей службы.
Пример добавления нескольких служб и различных свойств:
void add_mdns_services()
{
// Добавление служб:
mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0);
mdns_service_add(NULL, "_myservice", "_udp", 1234, NULL, 0);
// ПРИМЕЧАНИЕ: службы должны быть сначала добавлены, чтобы можно было
// установить их свойства.
// Настройка пользовательского экземпляра web-сервера.
mdns_service_instance_name_set("_http", "_tcp", "Jhon's ESP32 Web Server");
mdns_txt_item_t serviceTxtData[3] = {
{"board","{esp32}"},
{"u","user"},
{"p","password"}
};
// Установка данных txt для службы (освободит и заменит текущие данные):
mdns_service_txt_set("_http", "_tcp", serviceTxtData, 3);
// Изменение сетевого порта службы:
mdns_service_port_set("_myservice", "_udp", 4321);
}
[mDNS Query]
mDNS предоставляет методы для браузинга служб и распознавания IP-адресов (IPv4/IPv6) хоста. Результаты возвращаются в виде связанного списка объектов mdns_result_t.
Пример распознавания IP хоста:
void resolve_mdns_host(const char * host_name)
{
printf("Query A: %s.local", host_name);
struct ip4_addr addr;
addr.addr = 0;
esp_err_t err = mdns_query_a(host_name, 2000, &addr);
if(err){
if(err == ESP_ERR_NOT_FOUND){
printf("Host was not found!");
return;
}
printf("Query Failed");
return;
}
printf(IPSTR, IP2STR(&addr));
}
Пример распознавания локальных служб:
static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
void mdns_print_results(mdns_result_t * results)
{
mdns_result_t * r = results;
mdns_ip_addr_t * a = NULL;
int i = 1, t;
while(r){
printf("%d: Interface: %s, Type: %s\n",
i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
if(r->instance_name){
printf(" PTR : %s\n", r->instance_name);
}
if(r->hostname){
printf(" SRV : %s.local:%u\n", r->hostname, r->port);
}
if(r->txt_count){
printf(" TXT : [%u] ", r->txt_count);
for(t=0; t<r->txt_count; t++){
printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
}
printf("\n");
}
a = r->addr;
while(a){
if(a->addr.type == IPADDR_TYPE_V6){
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
} else {
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
}
a = a->next;
}
r = r->next;
}
}
void find_mdns_service(const char * service_name, const char * proto)
{
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
mdns_result_t * results = NULL;
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
if(err){
ESP_LOGE(TAG, "Query Failed");
return;
}
if(!results){
ESP_LOGW(TAG, "No results found!");
return;
}
mdns_print_results(results);
mdns_query_results_free(results);
}
Пример использования этих методов:
void my_app_some_method()
{
// Поиск esp32-mdns.local:
resolve_mdns_host("esp32-mdns");
// Поиск серверов HTTP:
find_mdns_service("_http", "_tcp");
// ... или файловых серверов:
find_mdns_service("_smb", "_tcp"); // общий доступ к файлам Windows
find_mdns_service("_afpovertcp", "_tcp"); // общий доступ к файлам Apple
find_mdns_service("_nfs", "_tcp"); // сервер NFS
find_mdns_service("_ftp", "_tcp"); // сервер FTP
// ... или сетевого принтера:
find_mdns_service("_printer", "_tcp");
find_mdns_service("_ipp", "_tcp");
}
[Оптимизация производительности]
Cкорость выполнения. mDNS создает задачу, и по делает это умолчанию с низким приоритетом 1 (опция CONFIG_MDNS_TASK_PRIORITY), если опция CONFIG_FREERTOS_UNICORE разрешена и прикреплена к CPU0 (CONFIG_MDNS_TASK_AFFINITY). Подробнее про оптимизацию скорости см. [3].
Использование RAM. mDNS создает задачи с размерами стека, сконфигурированным опцией CONFIG_MDNS_TASK_STACK_SIZE. Подробнее про оптимизацию использования ОЗУ см. [4].
Пример использования mDNS см. в папке examples репозитория mDNS [5].
[API mDNS]
Функция |
Описание |
mdns_init |
Инициализирует mDNS на имеющемся интерфейсе. |
mdns_free |
Остановит сервер DNS. |
mdns_hostname_set |
Установит имя хоста для mDNS, которое необходимо, если вы собираетесь представлять службы хоста (advertise services). |
mdns_delegate_hostname_add |
Добавит в базу данных сервера DNS сопоставление имени хоста (hostname) и его адреса (address) для удовлетворения запросов A/AAAA для имени хоста и служб, которые могут быть добавлены для этого хоста. |
mdns_delegate_hostname_remove |
Удалит делегированное имя хоста. Также будет удалена информация всех его служб. |
mdns_hostname_exists |
Запрашивает, было ли добавлено указанное имя хоста. |
mdns_instance_name_set |
Установит имя по умолчанию для экземпляра (сервера mDNS?). |
mdns_service_add |
Добавит службу на сервер mDNS. |
mdns_service_add_for_host |
Добавит службу в базу данных сервера mDNS, связанную с делегированным именем хоста. |
mdns_service_exists |
Проверяет, была ли добавлена служба для указанного имени хоста. |
mdns_service_exists_with_instance |
Проверяет, была ли добавлена служба для указанного экземпляра хоста. |
mdns_service_remove |
Удалит службу с сервера mDNS. |
mdns_service_remove_for_host |
Удалит службу из базы данных сервера mDNS, связанную с именем хоста. |
mdns_service_instance_name_set |
Установит имя экземпляра для службы. |
mdns_service_instance_name_set_for_host |
Установит имя экземпляра для службы с именем хоста. |
mdns_service_port_set |
Установит порт службы. |
mdns_service_port_set_for_host |
Установит порт службы для хоста. |
mdns_service_txt_set |
Заменит все элементы TXT для службы. |
mdns_service_txt_set_for_host |
Заменит все элементы TXT службы для хоста. |
mdns_service_txt_item_set |
Установит/добавит элемент TXT для записи TXT службы. |
mdns_service_txt_item_set_with_explicit_value_len |
Установит/добавит элемент TXT для записи TXT службы. |
mdns_service_txt_item_set_for_host |
Установит/добавит элемент TXT для записи TXT службы указанного хоста. |
mdns_service_txt_item_set_for_host_with_explicit_value_len |
Установит/добавит элемент TXT для записи TXT службы указанного хоста, с указанием длины текста. |
mdns_service_txt_item_remove |
Удалит элемент TXT для записи TXT службы. |
mdns_service_txt_item_remove_for_host |
Удалит элемент TXT для записи TXT службы указанного хоста. |
mdns_service_subtype_add_for_host |
Добавит подтип для службы. |
mdns_service_remove_all |
Удалит и освободит все службы из сервера mDNS. |
mdns_query_async_delete |
Удалит и завершит запрос. Вызывайте эту функцию только после окончания поиска! |
mdns_query_async_get_results |
Извлекает результаты по указателю поиска. Результаты доступны в виде указателя, возвращаемого из функции. Указатель на объект поиска должен быть удален вызовом mdns_query_async_delete, как только запрос завершится. Однако результаты должны быть освобождены вручную. |
mdns_query_async_new |
Асинхронный запрос к mDNS для имени хоста или службы. Состояние прогресса поиска должно быть проверено, и поиск должен быть удален вручную! |
mdns_query_generic |
Традиционный запрос mDNS. Все следующие методы являются производными из mdns_query_generic. |
mdns_query |
Опрашивает mDNS для информации о хосте или службе. Обратите внимание, что что при запросе типов PTR отправляется многоадресный запрос (multicast query), все другие типы посылают одноадресные запросы (unicast query). |
mdns_query_results_free |
Освободит результаты запроса. |
mdns_query_srv |
Опрашивает mDNS для получения записи SRV. |
mdns_query_txt |
Опрашивает mDNS для получения записи TXT. |
mdns_query_a |
Опрашивает mDNS для получения записи A. |
mdns_register_netif |
Регистрирует пользовательский esp_netif с функционалом mDNS, который по умолчанию запускается на предварительно сконфигурированных интерфейсах (STA, AP, ETH). Эта API-функция позволяет запустить службу на любом настроенном пользователем интерфейсе, либо с использованием стандартного драйвера WiFi или Ethernet, или любого другого вида драйвера, определенного пользователем. |
mdns_unregister_netif |
Отменяет регистрацию esp-netif, который уже был зарегистрирован в службе mDNS. |
mdns_netif_action |
Установит esp_netif в желаемое состояние, или выполнит желаемое действие, такое как разрешение/запрет этого интерфейса, или отправка пакетов оповещения в этот интерфейс. Подробнее см. [1]. |
Полное описание параметров и возвращаемых результатов из этих API-функций, а также связанных с ними макросов, перечислений и типов см. документацию [1].
[Ссылки]
1. ESP-IDF mDNS Service site:espressif.github.io. 2. DNS SRV (RFC 2782) Service Types site:dns-sd.org. 3. ESP-IDF Maximizing Execution Speed site:espressif.com. 4. ESP-IDF Minimizing RAM Usage site:espressif.com. 5. Репозиторий mDNS (espressif / esp-protocols). |