#ios #objective-c #sockets #bonjour #mdns
#iOS #objective-c #сокеты #bonjour #mdns
Вопрос:
У меня есть iPad, который не будет «видеть» устройства bonjour в сети. Итак, я хочу отправить пакет UDP MDNS, чтобы сеть предоставила IP-адрес последним устройствам в сети, чтобы я мог выполнить зеркальное отображение на iPad. Я могу создать сокет, но данные, которые я отправляю, неверны. Есть идеи?
struct icmphdr
{
u_int16_t qr; /* type sub-code */
u_int16_t opcode;
u_int16_t aa;
u_int16_t tc;
u_int16_t rd;
u_int16_t ra;
u_int16_t z;
u_int16_t ad;
u_int16_t cd;
u_int16_t rcode;
u_int16_t q_count;
}
// Create the socket connection
int sd = socket(AF_INET, SOCK_DGRAM, 0);
// Configure the port and ip we want to send to
struct sockaddr_in broadcastAddr; // Make an endpoint
memset(amp;broadcastAddr, 0, sizeof (broadcastAddr));
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_len = sizeof(broadcastAddr);
broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY);
broadcastAddr.sin_addr.s_addr = inet_addr("224.0.0.251");
broadcastAddr.sin_port = htons(5353); // Set port 5353
bind (sd, (struct sockaddr *)amp;broadcastAddr, sizeof(broadcastAddr));
struct icmphdr req;
req.qr=00; // Reponse: Message is query
req.opcode=00; // Opcode: Standard Query (0)
req.tc=00; // Truncated: Message is not truncated
req.rd=00; // Recursion desired: Don't do query recursively
req.z=00; // Z: reserved (0)
req.ad=00; // Non-authenticated data: Unacceptable
req.ra=02; // Questions: 2
req.cd = 00;
req.rcode = 00;
req.q_count = 00;
req.aa = 00;
if (sendto(sd, amp;req, sizeof(req), 00, (struct sockaddr*)amp;broadcastAddr, sizeof broadcastAddr)) {
NSLog(@"%s",strerror(errno));
}
close(sd);
Ответ №1:
во-первых, откуда вы знаете, что ваш iPad не видит устройства Bonjour? если это не очень ранняя версия iOS, она должна быть способна.
запросы Second — Bonjour (обычно) выполняются с DNS-запросами для записей PTR, а не ICMP. AFAIK, нет способа получить список всех устройств Bonjour в сети. таким образом, вы можете либо запросить интересующие вас сервисы, либо запросить _services ._dns-sd._udp.local чтобы получить список служб, затем выполните запрос для каждой из них.
в любом случае вашему пакету требуется некоторая информация о вопросе. google для поиска структуры пакетов DNS, вот краткое руководство по запросу PTR —
идентификатор — 2 байта, всегда нулевые флаги — 2 байта, ноль для количества вопросов запроса — 2 байта, в данном случае количество ответов на 1 — 2 байта, нулевое количество полномочий — 2 байта, нулевое дополнительное количество — 2 байта, ноль
далее следует ваш вопрос — имя (например, _airport._tcp.local) — в формате 3www6google3com0 тип — 2 байта, 12 для класса типа PTR — 2 байта, 1 для класса internet
это должно сработать.
однако обратите внимание, что перед тем, как приступить к этой проблеме, посмотрите, можете ли вы привязать() к порту 5353. это не позволяет мне это сделать, говорит, что адрес используется. я полагаю, ребята, которые портировали ответчик MDNS на iOS, забыли установить опцию «повторно использовать адрес» в своем сокете. итак, на этом все. спасибо, ребята.
Комментарии:
1. На самом деле, вы можете привязаться к порту 5353. Вот код для этого // Установить параметр сокета для повторного использования порта 5353, если (setsockopt (sd, SOL_SOCKET, SO_REUSEPORT, amp;on, sizeof (on)) < 0) { NSLog (@»сбой setsockopt(): %s», strerror(errno)); } // Привязать порт 5353 к iPad, если(привязать (sd, (struct sockaddr *)amp;client, sizeof( клиент)) < 0){ NSLog(@»Ошибка привязки: %s», ошибка strerror(errno)); }
2. первая привязка порта должна установить опцию повторного использования порта для работы дальнейших привязок. если первая привязка этого не делает, последующих привязок быть не может. расскажите мне об этом, все мои приложения mDNS перестали работать с Yosemite, поскольку новая функция обнаружения не устанавливает эту опцию. однако я слышал, что El Capitan возвращается к mDNSResponder, который устанавливает опцию повторного использования (если только они теперь не сломали и это). ух ты! жизнь непростая для нас, типов MDNS.