質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

Winsock による IPv6 マルチキャストの実装を教えてください。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 2,641

izuki_y

score 53

 Winsock による IPv6 マルチキャストの実装

 開発環境

OS: Winsows 7 Professional 32bit
IDE: Visual Studio 2013 EE
言語: C言語

1台のPC内でサーバとクライアントを立ててIPv6のマルチキャスト(UDP)を使ってメッセージの送受信が行えるか検証をしています。
IPv4のブロードキャストの様にAP内に接続された不特定の機器に対してメッセージを送り、対応するマシンのIPv6アドレスを取得するプログラムを作りたいと思っています。
取り合えず、IPv6アドレスを使いクライアントからサーバに対して"HELLO"メッセージを送りサーバで受信メッセージを表示するプログラムを作ってみましたが
上手く送受信が行えていません。
クライアントはsendtoで投げていますが、サーバがrecvから戻ってきません。
ログを取ろうとしてもNICを通って居ないのでWiresharkでログを拾う事も出来ません。

マルチキャストアドレスの指定などが間違っているのでしょうか?

[クライアント]
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>

// 使わない
//static const char multicast_addr[16+1] = { 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };

int __cdecl main(int argc, char **argv) 
{
    SOCKET sock;
    struct sockaddr_in6 addr = {0};
    int addr_size;
    WSADATA wsaData;
    int retval;

    retval = WSAStartup(MAKEWORD(2,2), &wsaData);

    sock = socket(AF_INET6, SOCK_DGRAM, 0);

    addr.sin6_family = AF_INET6;
    addr.sin6_port =htons(5001);


    WSAStringToAddress("ff02::1", AF_INET6, NULL, (LPSOCKADDR)& addr, &addr_size); //通信相手として IPv6 のマルチキャストアドレスを指定します
    //memcpy(addr.sin6_addr.u.Byte, multicast_addr, sizeof(multicast_addr));


    sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));

    closesocket(sock);

    WSACleanup();

    return 0;
}
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int __cdecl main(int argc, char **argv) 
{
    WSADATA     wsaData;
    SOCKET     server_sockets;
    int retval,
    struct sockaddr_in6 addr;
    char buf[2048];

    retval = WSAStartup(0x202,&wsaData);

    server_sockets = socket(AF_INET6, SOCK_DGRAM, 0);

    memset( (void*)addr, 0x00, sizeof(sockaddr_in6));
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(5001);
    addr.sin6_addr = in6addr_any;

    bind(server_sockets, (struct sockaddr *)&addr, sizeof(addr));



    memset(buf, 0, sizeof(buf));
    recv(server_sockets, buf, sizeof(buf), 0);

     printf("%s\n", buf);

     closesocket(server_sockets);

     WSACleanup();

    return 0;
}

C

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

UDPマルチキャストパケットを受信するには、受信側でマルチキャストグループに参加する必要があります。この操作は IPv4/v6 いずれでも必要です。IPv6の場合はIPPROTO_IPV6/IPV6_ADD_MEMBERSHIPソケットオプションを利用します。

詳細は UDPでマルチキャストを使う や Winsockを使って、Multicastプログラムしてみよう を参照ください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/09 00:03 編集

    遅くなってすみません。
    回答ありがとうございました。

    マルチキャストを使うためには受信側でのマルチキャストグループ参加が必須だったんですね。
    オプションとばかり思ってたので気づきませんでした。
    おかげで通信を行う事が出来ました。
    マルチキャストグループと言うのは受信側(ここではサーバ側)が任意で決めるものなのでしょうか?
    ブロードキャストの様に255.255.255.255を出すとノード全体に投げる様な仕組みを想像していたのでマルチキャストグループはクライアントとサーバで同じ物を事前に用意しておかなければいけないのか?と思っています。
    もし参考資料などがあれば教えてください。

    作り直したソースは自己解決の所に記載いたしました。

    キャンセル

  • 2016/06/09 09:46

    マルチキャストアドレスはどちらかと言えば、送受信側の両方で取り決めておくものです。例えば FF02::1 は「リンクローカルの全ノード向け」と予め決められています。

    http://www.infraexpert.com/study/ipv6z10.html も参考にどうぞ。

    キャンセル

0

yohhoy さんの回答を元にマルチキャストに対応させてみました。
アドレスの指定が本当にこれでいいかは自信がありませんが。

[クライアント側]

#include <winsock2.h>
#include <ws2tcpip.h>

int __cdecl main(int argc, char **argv)
{
SOCKET client_sock;
WSADATA wsaData;
struct sockaddr_in6 addr6;

int retval;

retval = WSAStartup(MAKEWORD(2, 2), &wsaData);

client_sock = socket(AF_INET6, SOCK_DGRAM, 0);

/* init */
memset((void*)&addr6, 0x00, sizeof(sockaddr_in6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(5001);
InetPton(AF_INET6, "FF02::1", &(addr6.sin6_addr));

sendto(client_sock, "HELLO", 5, 0, (struct sockaddr *)&addr6, sizeof(addr6));

closesocket(client_sock);

WSACleanup();

return 0;
}
[サーバ側]
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

int __cdecl main(int argc, char **argv) 
{
    SOCKET server_sockets;
    WSADATA wsaData;
    struct sockaddr_in6 addr6;
    struct ipv6_mreq mreq6;

    int retval;
    char buf[2048]={0};

    retval = WSAStartup(0x202,&wsaData);

    server_sockets = socket(AF_INET6, SOCK_DGRAM, 0);

    /* init */
    memset( (void*)&addr6, 0x00, sizeof(sockaddr_in6));
    addr6.sin6_family = AF_INET6;
    addr6.sin6_port = htons(5001);
    addr6.sin6_addr = in6addr_any;

    bind(server_sockets, (struct sockaddr *)&addr6, sizeof(addr6));

    // setsockoptは、bind以降で行う必要あり
    memset(&mreq6, 0, sizeof(mreq6));
    mreq6.ipv6mr_interface = INADDR_ANY;
    InetPton(AF_INET6, "FF02::1", &(mreq6.ipv6mr_multiaddr));

    // マルチキャスト受信側ではsetsocketoptの設定は必須
    if (setsockopt(server_sockets,
        IPPROTO_IPV6,
        IPV6_ADD_MEMBERSHIP,
        (char *)&mreq6, sizeof(mreq6)) != 0) {
        printf("setsockopt : %d\n", WSAGetLastError());
        return 1;
    }

    recv(server_sockets, buf, sizeof(buf), 0);

    printf("%s\n", buf);

    closesocket(server_sockets);

    WSACleanup();

    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る