2012-04-01 20 views
0

私はプロトコルをテストするためにオーバーレイネットワークシステムを構築しています(Uni research)。さまざまなソースからパケットを受信するためには、参加してマルチキャストグループから離れる必要があります。マルチキャストグループLinux - 参加と離脱

ソケットの正しい設定がわからないので、ソケットを閉じてマルチキャストグループを離れてから、後で同じマルチキャストグループに再び参加することができます。同じマルチキャストグループに参加しようとすると「bind error: Address already in use」と表示されます。

//for setting up individual groups 
int setUpForGroup(struct locgro_node* node, const char* port) 
{ 
    char mcastaddr[INET6_ADDRSTRLEN]; 

    struct in6_addr* full_addr_gro = &(node->group); 
    if(NULL == inet_ntop(AF_INET6, full_addr_gro, mcastaddr, INET6_ADDRSTRLEN)) 
    { 
     printf("error inet_pton, retval: \n"); 
     return -1; 
    } 

    if (buildAdd(mcastaddr, port, AF_INET6, SOCK_DGRAM, &(node->addr_st)) <0) 
    { 
     fprintf(stderr, "get_addr error:: could not find multicast, address=[%s] port=[%s]\n", mcastaddr, port); 
     return -1; 
    } 

    node->sockfd = socket(AF_INET6, SOCK_DGRAM, 0); 

    if (bind(node->sockfd, (struct sockaddr *)&(node->addr_st), sizeof(node->addr_st)) < 0) { 
     perror("bind error:: "); 
     close(node->sockfd); 
     return -1; 
    } 

    if (joinGroup(node->sockfd, 0 , 8, &(node->addr_st)) <0) { 
     close(node->sockfd); 
     return -1; 
    } 

    return 0; 
} 
//internal function 
int joinGroup(int sockfd, int loopBack, int mcastTTL, struct sockaddr_in6 *addr_st) 
{ 
    int r1, r2, r3, retval; 
    retval=-1; 
    struct ipv6_mreq mreq6; 

    memcpy(&mreq6.ipv6mr_multiaddr, &((addr_st)->sin6_addr), sizeof(struct in6_addr)); 

    mreq6.ipv6mr_interface= 0; // allow any interface 

    //set the loopback case 
    r1 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopBack, sizeof(loopBack)); 
    if (r1<0) perror("joinGroup:: IPV6_MULTICAST_LOOP:: "); 

/* 
    setsockopt(sock_fd, IPPROTO_IPV6, SO_REUSEADDR, &mreq6, sizeof(mreq6)); 

    setsockopt(sock_fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &multicast_req, sizeof(multicast_req)); 
*/ 
    //set the time to live for the packets (hops) 
    r2 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)); 
    if (r2<0) perror("joinGroup:: IPV6_MULTICAST_HOPS:: "); 

    //add this address to the group 
    r3 = setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)); 
    if (r3<0) perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: "); 

    if ((r1>=0) && (r2>=0) && (r3>=0)) retval=0; 

    return retval; 
} 


//internal function 
int buildAdd(const char *hostname, const char *service, int family, int socktype, struct sockaddr_in6 *addr_st) 
{ 
    struct addrinfo hints, *res, *ressave; 
    int n, sockfd, retval; 

    retval = -1; 

    memset(&hints, 0, sizeof(struct addrinfo)); 
    hints.ai_family = family; 
    hints.ai_socktype = socktype; 

    n = getaddrinfo(hostname, service, &hints, &res); 

    if (n <0) 
    { 
     fprintf(stderr, "getaddrinfo error: [%s]\n", gai_strerror(n)); 
     return retval; 
    } 

    ressave = res; 

    sockfd=-1; 
    while(res) 
    { 
     sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 

     if (!(sockfd < 0)) 
     { 
      int opval = 1; 
      setsockopt(sockfd, IPPROTO_IPV6, SO_REUSEADDR, &opval, res->ai_addrlen); 

      if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) 
      { 
      //to test that the address really is correct 
       close(sockfd); 
       memcpy(addr_st, res->ai_addr, sizeof(*addr_st)); 
       retval=0; 
       break; 
      } 
      perror("build addr : bind error"); 
      close(sockfd); 
      sockfd=-1; 
     } 
     res=res->ai_next; 
    } 

    freeaddrinfo(ressave); //free the struct 

    return retval; 
} 

これは私がグループに参加するために使用した機能です。 私を残すだけで実行します(つまり、別の関数の内部で起こる)

struct ipv6_mreq mreq6; 
    memcpy(&mreq6.ipv6mr_multiaddr, &(temp_lnode->group), sizeof(struct in6_addr)); 
    mreq6.ipv6mr_interface= 0; // allow any interface 
    setsockopt(temp_lnode->sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)); 

    close(temp_lnode->sockfd); //close socket 

私はビルドアドレス関数内アドレスをバインドしようとしたとき、私は「既に使用中アドレス」エラーを取得しています。 私はSO_REUSEADDRを設定して解決しようとしましたが、それは助けにはならず、DROP_MEMBERSHIPも追加しましたが、バインドはまだ失敗します。

私はそれを動作させるためにバインドする必要がありますか?この問題がなければ、グループの参加や離脱を許可するにはどうすればよいですか?私は30秒間隔でこれを行う必要があります。

どうもありがとう M

+0

問題が解決しました。 初めてグループを作成するときにSO_REUSEADDRを使用し、DROP_MEMBERSHIPを使用するとそのトリックを行います。あるケースではDROP_MEMBERSHIPを見ていないことに気づいたので、どちらが実際の修正を行ったのかはわかりません。マルチキャストを扱うときに常にSO_REUSEADDRを設定することをお勧めします。 乾杯、M – unixsnob

+0

@ unixsnob:あなたはそれをあなた自身で解決しました。あなたはおそらくあなたの答えとしてそれを置くことができます。オフトピック:コード内のコメントを無効にしてください - 本当に簡単です:例えば、//構造体が値を持たない。 – Jayan

答えて

1

解決roblem。最初にグループを作成するときにSO_REUSEADDRを使用し、DROP_MEMBERSHIPを使用するとそのトリックを行います。あるケースではDROP_MEMBERSHIPを見ていないことに気づいたので、どちらが実際の修正を行ったのかはわかりません。マルチキャストを扱うときに常にSO_REUSEADDRを設定することをお勧めします。乾杯、M

関連する問題