2010-01-12 81 views
3

所以,我一直在努力弄清楚爲什麼這不起作用,但我沒有線索。我設法從iPhone發送數據包並在我的Mac上接收數據包。並根據tcpdump我的mac正確發送數據包。另外,如果我在模擬器中運行它,它工作正常。這使我相信這是一個網絡問題,但我不知道這可能是什麼,所以我希望(!)這是下面的東西。爲什麼沒有收到(UDP組播)數據包?

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不接收該數據包。此外,羅伯特完全正確的是,它在模擬器上工作的原因是由於環回。

+0

問題是什麼?你期望什麼,什麼不是碰巧? – 2010-01-12 15:02:08

回答

1

我需要到INADDR_ANY更改爲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; 
4

我假設這是recv方......在組播套接字安裝看起來很好。你說它可以在模擬器上工作,但不是真實的網絡,對嗎?存在一個問題,即您的網絡設備,尤其是任何路由器,可能還有其他設備,可能需要明確設置爲允許轉發廣播和/或多播數據包。這些類型的數據包通常默認放置在網絡邊緣。這裏還有一個長處 - 如果你在同一臺計算機上同時運行發送者和接收者,並關閉IP_MULTICAST_LOOP,那麼你將不會得到任何數據包,因爲它會禁用多播回送接口。這就是我所能想到的,沒有關於你的設置的更多信息和/或看到更多的代碼。

+0

添加了網絡代碼的其餘部分,並且您對環回是100%正確的,因爲它是在模擬器上工作的原因。 – Jonathon 2010-01-13 00:58:43

0

我有一個類似的問題想測試我的電腦上,通過tcpreplay,其他2個人電腦的A和B之間的Wireshark的記錄一些數據交換B.所以我適應舊記錄是這樣的:

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

然後

tcpreplay -T nano --verbose -i lo newrecordfile 

但我APPLI陽離子recv()失敗。

這個問題可能與tcpreplay的環回限制有關,所以我決定在用tcprewrite重新生成合適的記錄文件和新IP之後,重新從PC向PC發送數據。此時tcpdump在接收端顯示了一些東西,但程序recv()總是失敗。

最後我發現的,其原因是舊的MAC地址和路由器之間的兩臺PC的存在:

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