3

そのため、なぜこれが機能しないのかを正確に理解しようとしていますが、手がかりがありません。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 がパケットを受信して​​いない理由を知りたいと思います。また、Robert は、シミュレーターで動作していた理由はループバックによるものであるという点で完全に正しいです。

4

3 に答える 3

4

私はこれが recv 側であると想定しています...表面上、マルチキャスト ソケットのセットアップは問題ないように見えます。シミュレーターでは動作するが、実際のネットワークでは動作しないとおっしゃいましたよね? ブロードキャストおよび/またはマルチキャスト パケットの転送を許可するには、ネットワーク機器、特に任意のルーター、場合によっては他の機器も明示的に設定する必要があるという問題があります。これらの種類のパケットは通常、デフォルトでネットワークの端でドロップされます。別のロング ショットを次に示します。送信側と受信側の両方を同じマシンで実行し、IP_MULTICAST_LOOP をオフにすると、マルチキャスト ループバック インターフェイスが無効になるため、パケットを取得できません。セットアップに関する詳細情報がなくても、および/またはもう少しコードを見なくても、私が考えることができるのはこれだけです。

于 2010-01-12T18:59:41.430 に答える
1

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;
于 2010-02-07T07:05:41.113 に答える
0

私の PC で tcpreplay を使用して、他の 2 台の PC の A と B の間で Wireshark によって記録されたデータ交換をテストしようとして、同様の問題が発生しました。

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

その後

tcpreplay -T nano --verbose -i lo newrecordfile

しかし、私のアプリケーション recv() は失敗します。

問題は tcpreplay のループバック制限に関連している可能性があるため、tcprewrite によって新しい IP で適切なレコード ファイルを再生成した後、PC から PC にデータを再送信することにしました。この時点で、tcpdump は私の受信側で例外として物事を示しましたが、プログラム recv() は常に失敗します。

最後に、古い MAC アドレスと、2 台の 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
于 2014-08-20T08:56:38.707 に答える