web-dev-qa-db-ja.com

C-UDP /マルチキャストソケットのインターフェイスを選択

マルチキャストリスナー/送信者の例 を変更して、UDP /マルチキャストソケットを特定のインターフェースにバインドし、を使用しないINADDR_ANYマクロ。

インターフェイスのIPv4アドレスを持っています。以下を試しましたが、ソケットがUDP(ユニキャスト、ブロードキャスト、マルチキャスト)パケットを受信しません。

struct sockaddr_in addr;
int fd, nbytes;
socklen_t  addrlen;
struct ip_mreq mreq;

// my_ipv4Addr equals current IP as String, e.g. "89.89.89.89"

// create what looks like an ordinary UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    exit(1);
}

// set up addresses
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
// [-]    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
addr.sin_addr.s_addr = inet_addr(my_ipv4Addr); 
addr.sin_port = htons(port);

// bind socket
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    perror("bind");
    exit(1);
}

// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-]    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))< 0) {
    perror("setsockopt");
    exit(1);
}

編集:

私のプログラムの目的を説明しましょう。 ネットワークがブロードキャスト/マルチキャストをサポートしているかどうかをチェックする小さなツールを書いています。したがって、私は2つのインターフェースを持つシステムを所有し、Interface1を介して送信しますaパケットをマルチキャストし、Interface2で受信しようとします。しかし:パケットはネットワークを通過しますが、loopackデバイスではありません

アイデアは、thread1/interface1のマルチキャストループバックを次のようにブロックすることです。

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

そして、thread2/interface 2のインターフェイス固有のリッスン。 Tcpdumpは、パケットが到着していることを示していますが、上記の構成ではドロップされます。

16
user22602


addr.sin_addr.s_addr=inet_addr(my_ipv4Addr);
bind(sockfd,(SA*)&addr,sizeof(addr));
パケットはマルチキャストグループにのみ送信できます。
しかし、my_ipv4Addrから送信されたパケットであっても、パケットを受信することはできません。

したがって、_addr.sin_addr.s_addr_htonl(INADDR_ANY)でなければなりません。


mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
マルチキャストグループからすべてのパケットを受信できます。
しかし、それはデフォルトのインターフェース(おそらくeth0)でパケットを送信します、
指定したものではありません(eth1など)。
これは効果がありません。


setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,ETH1,strlen(ETH1));
インターフェイスETH1を介してパケットを送信できます
ただし、ETH1に関連付けられたIPから送信されるパケットのみを受信できます。
他のクライアントからのパケットを受信することはできません。


mreq.imr_interface.s_addr=inet_addr(my_ipv4Addr);
setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&mreq.imr_interface,sizeof(struct in_addr);
my_ipv4addrに関連付けられたインターフェイスを介してパケットを送信できます。
また、マルチキャストグループ内の任意のクライアントからの任意のパケットを受信できます。

7
PLA

マルチキャストトラフィックを受信するためにソケットをバインドする場合、ローカルアドレスにバインドすると、Windows以外のシステムでマルチキャストパケットを受信できなくなります。

特定のアドレスにバインドする機能を備えた [〜#〜] uftp [〜#〜] のバージョン3.6をリリースしたときに、これを最初に発見しました。 Windowsはそれをうまく処理しますが、Linuxシステムでは、マルチキャストパケットはアプリによって受信されませんでした。次のリリースで機能を削除する必要がありました。

マルチキャストアドレスに直接バインドすることが許可されていることに注意してください。

addr.sin_addr.s_addr = inet_addr(group);

この場合、そのソケット上のそのマルチキャストアドレスのトラフィックのみを受信します。ただし、受信するには、特定のインターフェイスのマルチキャストグループに参加する必要があります。

同じソケットで複数のマルチキャストアドレスからデータを受信する場合は、INADDR_ANYにバインドする必要があります。

4
dbush
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); 
//addr.sin_addr.s_addr = inet_addr(my_ipv4Addr); 
addr.sin_port = htons(port);

mreq.imr_multiaddr.s_addr = inet_addr(group);
// [-]    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);

あなたは私のようにあなたのコードを編集する必要があるだけです。

4
sina

理解のためにコードを簡略化したか、何かを見逃したか、

これは構造体です

struct ip_mreqn {
    struct in_addr imr_multiaddr; /* IP multicast group
                                     address */
    struct in_addr imr_address;   /* IP address of local
                                     interface */
    int            imr_ifindex;   /* interface index */
};

ip manページ-IP_ADD_MEMBERSHIP

しかし、あなたは言及しています

mreq.imr_interface.s_addr = inet_addr(my_ipv4Addr);

imr_interfaceとは何ですか?コンパイルできますか?

読みやすくするために上記の名前を書いたばかりの場合は、インターフェースインデックス、つまりimr_ifindexを、接続する特定のインターフェースに入力してみましたか?.

私の推測では、imrr_addressを残してインターフェイスインデックスのみを割り当てると、そのインターフェイスにバインドしてパケットを受信するはずです。それが役立つかどうかを確認します。

0
fkl