简体   繁体   中英

Why are (UDP multicast) packets not being received?

So, I've been trying to figure out exactly why this isn't working but I haven't a clue. I've managed to send packets from the iPhone and receive them on my Mac. And according to tcpdump my mac is correctly sending the packets. Additionally, if I run this in the simulator it works fine. This leads me to believe that it's a network problem, but I have no idea what that could be, so I was hoping(!) that it's something below.

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);

EDIT:

The code above is for the receiving end on the iPhone.

I'm using the java code below to talk to the iPhone (this is condensed). The packet that gets sent is not received by the iPhone but the mac receives the packet that the iPhone sends.

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));

This is the code I'm using to send from the 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));

So, to clarify the question, I want to know why the iPhone isn't receiving the packet. Also, Robert is completely right that the reason it was working on the simulator is due to the loopback.

I'm assuming that this is the recv side... On the face the multicast socket setup looks fine. You say it works on the simulator but not a real network, correct? There is an issue that your network equipment, specifically any routers, possibly other equipment as well may need to be explicitly set up to allow forwarding of broadcast and / or multicast packets. These kinds of packet are usually dropped at the edge of networks by default. Here's another long shot - if you run both the sender and receiver on the same machine and turn off IP_MULTICAST_LOOP then you won't get any packets as it disables the multicast loopback interface. That's all I can think of without more info on your setup and / or seeing a bit more code.

I needed to change the INADDR_ANY to the broadcastIP...

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;

I had a similar problem trying to test on my PC, by tcpreplay, some data exchange recorded by Wireshark between other 2 PC's A and B. So I adapt the old record this way:

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

and then

tcpreplay -T nano --verbose -i lo newrecordfile

But my application recv() fail.

The problem could be related to loopback limit of tcpreplay, so I decide to resend the data from PC to PC, after regenerating suitable recordfile with new IP's by tcprewrite. At this point tcpdump showed things as excepted on my receiving-end, but the program recv() always fail.

Finally I found out the reason of that were the old MAC addresses and the presence of a router between the two PC's:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM