Как отправлять широковещательные пакеты UDP через все интерфейсы в Objective-C / OS X 10.8 (DHCP)
Я создаю небольшую утилиту, которая должна обслуживать IP-адрес и параметры по BOOTP на моем MacBook Pro.
Я использовал библиотеку AsyncUdpSocket из GitHub (спасибо RobbieHanson), и когда моя машина настроена только с подключенным проводным Ethernet (Airport Off), тогда он работает. Однако, как только я включаю свой Wi-Fi, все ответы на широковещательные рассылки переходят по интерфейсу Wifi. Это приводит к тому, что проводные клиенты не получают ответа.
Код инициализации / получения:
if (![socket bindToAddress:@"0.0.0.0" port:67 error:&err])
NSLog(@"Error: unable to bind (%@)", [err localizedDescription]);
[socket enableBroadcast:YES error:&err];
[socket receiveWithTimeout:-1 tag:0];
Отправить код:
[sock sendData:packetData toHost:@"255.255.255.255" port:68 withTimeout:-1 tag:0];
Я уверен, что должен быть способ сделать это, но это моя первая программа для OS X, и я изо всех сил стараюсь освоить мой этикет для поиска в Google, чтобы он подходил фреймворкам:)
ОБНОВИТЬ
Сегодня вечером я испортил свой код и проверил, что делает AsyncUdpSocket, когда я его вызываю. По сути, у меня следующая ситуация; если я позвоню bindToAddress
и поставка 10.0.0.1
(адрес назначен моей ETH NIC), тогда я не получаю никаких пакетов, и я не могу их отправить. Однако, если я пройду nil
в метод, то я могу отправить сообщение и получить широковещательные сообщения - недостатком является то, что отправка происходит через мой WIFI NIC (маршрут по умолчанию)
На заднем плане - AsyncUdpSocket
библиотека зовет CFSocketSetAddress
либо с IFADDR_ANY, если указано значение nil, либо с заполненной структурой IFADDR 10.0.0.1, если она указана. Ошибки не выдаются, и поэтому следует ожидать, что сработает.
Есть идеи? Я иду вверх по стене и просто хочу, чтобы это было решено. Мне действительно нравится асинхронная природа библиотеки, поэтому я не хочу ее выбрасывать.
1 ответ
Я думаю, что вы должны
- Получить список всех сетевых интерфейсов на вашем компьютере,
- Для каждого интерфейса создайте сокет и привяжите его к адресу интерфейса.
- Отправить / получить на всех сокетах, по одному для каждого интерфейса.
Часть 1 может быть сделана, например, с getifaddrs()
(введите "man getifaddrs" в Терминале). Я не знаю, есть ли в CoreFoundation более простая в использовании функция.