Ich baue ein Overlay-Netzwerk-System, um ein Protokoll zu testen (Uni Research). Ich muss Multicast-Gruppen verbinden und verlassen, um Pakete von verschiedenen Quellen zu empfangen.Multicast-Gruppen Linux - Verbinden und Verlassen
Ich bin nicht sicher über die korrekte Einrichtung des Sockets, so dass ich den Socket schließen und die Multicast-Gruppe verlassen und dann wieder die gleiche Multicast-Gruppe später verbinden kann. Wenn ich versuche, der gleichen Multicast-Gruppe beizutreten, bekomme ich "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;
}
Dies sind die Funktionen, die ich für den Beitritt zu einer Gruppe verwendet habe. Wenn ich einfach verlassen tun: (die in einer anderen Funktion geschieht)
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
Ich bin eine „Adresse bereits verwendet“ Fehler bekommen, wenn ich versuche, die Adresse in der Build-Adresse Funktion zu binden. Ich habe versucht, das zu lösen, indem ich SO_REUSEADDR gesetzt habe, aber es hat nicht geholfen, auch die DROP_MEMBERSHIP hinzugefügt, aber die Bindung schlägt immer noch fehl.
Muss ich binden, damit es funktioniert? Was soll ich anrufen oder tun, um Gruppen ohne diese Probleme beitreten und verlassen zu können? Ich würde dies in Abständen von 30s tun müssen.
Vielen Dank M
Problem gelöst. Verwenden Sie SO_REUSEADDR beim ersten Erstellen der Gruppen und verwenden Sie DROP_MEMBERSHIP den Trick. Ich bin mir nicht sicher, welches die eigentliche Reparatur war, da ich erkannte, dass ich DROP_MEMBERSHIP in einem Fall nicht sah, wie auch immer ich gelesen habe, dass es ratsam ist, SO_REUSEADDR immer einzustellen, wenn Multicast behandelt wird. Prost, M – unixsnob
@ unixsnob: gut, dass Sie es selbst gelöst haben. Sie können das wahrscheinlich als Ihre Antwort verwenden. Offtopic: Bitte machen Sie Kommentare im Code ungültig, die wirklich trivial sind: zB // free the struct hat keinen Wert. – Jayan