Почему (многоадресные UDP-пакеты) не принимаются? - PullRequest
3 голосов
/ 12 января 2010

Итак, я пытался выяснить, почему это не работает, но я понятия не имею.Мне удалось отправить пакеты с iPhone и получить их на моем Mac.И согласно tcpdump мой mac правильно отправляет пакеты.Кроме того, если я запускаю это в симуляторе, он работает нормально.Это заставляет меня поверить, что это проблема с сетью, но я понятия не имею, что это может быть, поэтому я надеялся (!), Что это что-то ниже.

CFSocketContext socketContext = {0, self, NULL, NULL, NULL};
advertiseSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketDataCallBack, (CFSocketCallBack)&advertiseCallBack, &socketContext);

int yes = 1;
setsockopt(CFSocketGetNative(advertiseSocket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));

u_char loop = 0;
setsockopt(CFSocketGetNative(advertiseSocket), IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); 

unsigned char ttl = 64;
setsockopt(CFSocketGetNative(advertiseSocket), IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));        

struct sockaddr_in addressData;
memset(&addressData, 0, sizeof(addressData));
addressData.sin_len = sizeof(addressData);
addressData.sin_family = AF_INET;
addressData.sin_port = htons(broadcastPort);
addressData.sin_addr.s_addr = htonl(INADDR_ANY);
NSData *address = [NSData dataWithBytes:&addressData length:sizeof(addressData)];
CFSocketSetAddress(advertiseSocket, (CFDataRef)address);

struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(broadcastIP);         
mreq.imr_interface.s_addr = INADDR_ANY;

setsockopt(CFSocketGetNative(advertiseSocket), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

// set up the run loop sources for the sockets
CFRunLoopRef cfrl = CFRunLoopGetCurrent();
CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, advertiseSocket, 0);
CFRunLoopAddSource(cfrl, source, kCFRunLoopCommonModes);
CFRelease(source);

РЕДАКТИРОВАТЬ:

Код выше предназначен для принимающей стороны на iPhone.

Я использую код Java ниже, чтобы поговорить с iPhone (это сжато).Отправленный пакет не получен iPhone, но Mac получает пакет, который отправляет iPhone.

String ident = broadcastKey;
MulticastSocket socket = new MulticastSocket(broadcastPort);
InetAddress group = InetAddress.getByName(broadcastIP);
socket.joinGroup(group);
socket.setTimeToLive(64);
socket.setLoopbackMode(true);
byte [] key = ident.getBytes("UTF-16BE");
byte [] request = Arrays.copyOf(key,key.length+2);
System.out.println(Arrays.toString(request));
DatagramPacket packet = new DatagramPacket(request, request.length, group, broadcastPort);
socket.send(packet);
byte [] res = new byte[1024];
packet = new DatagramPacket(res, res.length);
socket.receive(packet);
System.out.println(Arrays.toString(res));

Этот код я использую для отправки с iPhone

NSData *toSend = [broadcastIdentifier dataUsingEncoding:NSUTF16BigEndianStringEncoding];
struct in_addr        localInterface;
struct sockaddr_in    groupSock;
int                   sd;
int                   datalen;

sd = socket(AF_INET, SOCK_DGRAM, 0);
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr(broadcastIP);
groupSock.sin_port = htons(broadcastPort);
localInterface.s_addr = INADDR_ANY;
setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface));
sendto(sd, [toSend bytes], [toSend length], 0, (struct sockaddr*)&groupSock, sizeof(groupSock));

Итак, чтобы прояснить вопрос, я хочу знать, почему iPhone не получает пакет.Кроме того, Роберт совершенно прав, что причина, по которой он работал на симуляторе, связана с обратной связью.

Ответы [ 3 ]

4 голосов
/ 12 января 2010

Я предполагаю, что это сторона recv ... На первый взгляд настройка сокета многоадресной рассылки выглядит хорошо.Вы говорите, что это работает на симуляторе, но не в реальной сети, правильно?Существует проблема, заключающаяся в том, что ваше сетевое оборудование, в частности любые маршрутизаторы, а также, возможно, другое оборудование, возможно, должно быть явно настроено для пересылки широковещательных и / или многоадресных пакетов.Эти типы пакетов обычно отбрасываются на границе сетей по умолчанию.Вот еще один длинный шаг - если вы запустите и отправителя, и получателя на одной машине и отключите IP_MULTICAST_LOOP, вы не получите никаких пакетов, так как это отключает многоадресный интерфейс обратной связи.Это все, что я могу придумать, не имея дополнительной информации о вашей настройке и / или увидев немного больше кода.

1 голос
/ 07 февраля 2010

Мне нужно было изменить INADDR_ANY на широковещательную рассылку IP ...

struct sockaddr_in addressData;
memset(&addressData, 0, sizeof(addressData));
addressData.sin_len = sizeof(addressData);
addressData.sin_family = AF_INET;
addressData.sin_port = htons(broadcastPort);
addressData.sin_addr.s_addr = inet_addr(broadcastIP);
NSData *address = [NSData dataWithBytes:&addressData length:sizeof(addressData)];
if (kCFSocketSuccess != CFSocketSetAddress(advertiseSocket, (CFDataRef)address)) {
    [self stopBeforeStart];
    [self connectionFailed];
    return;
}

struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(broadcastIP);         
mreq.imr_interface.s_addr = INADDR_ANY;
0 голосов
/ 20 августа 2014

У меня была похожая проблема, когда я пытался протестировать на моем ПК с помощью tcpreplay некоторый обмен данными, записанный Wireshark, между двумя другими ПК A и B. Поэтому я адаптирую старую запись следующим образом:

tcprewrite --pnat=A-IP:loIP,B-IP:loIP -i oldrecordfile -o newrecordfile

, а затем

tcpreplay -T nano --verbose -i lo newrecordfile

Но мое приложение recv () не работает.

Проблема может быть связана с лимитом обратной петли tcpreplay, поэтому я решил переслать данные с ПК на ПК после регенерации подходящего файла записи с новыми IP-адресами с помощью tcprewrite. В этот момент tcpdump показывал вещи как исключение на моем приемном конце, но программа recv () всегда терпела неудачу.

Наконец, я выяснил причину старых MAC-адресов и наличия маршрутизатора между двумя ПК:

tcprewrite --pnat=oldA-IP:newA-IP,oldB-IP:newB-IP --enet-smac=newA-MAC,newA-MAC --enet-dmac=newB-MAC,newB-MAC -i oldrecordfile -o newrecordfile
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...