无法使用 IPv6 进行多播
Unable to multicast using IPv6
这是发送方和接收方(组合)的代码。
int main (int argc, char *argv[]) {
struct in6_addr localInterface;
struct sockaddr_in6 groupSock;
// socket descriptor for multicast
int sd;
char databuf[10];
// length of message
int datalen = sizeof(databuf);
/* Create a datagram socket on which to send/receive. */
sd = socket(AF_INET6, SOCK_DGRAM, 0);
if(sd < 0) {
perror("Opening datagram socket error");
exit(1);
}
else {
printf("Opening the datagram socket...OK.\n");
}
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else {
printf("Setting SO_REUSEADDR...OK.\n");
}
}
/* Initialize the group sockaddr structure with a */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin6_family = AF_INET6;
// address of the group
// groupSock.sin6_addr = inet6_addr("ff5e::/16");
inet_pton(AF_INET6, "ff5e::/16", &(groupSock.sin6_addr));
groupSock.sin6_port = htons(4321);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
char *ip_address = argv[2];
inet_pton (AF_INET6, ip_address, &(localInterface.s6_addr));
memset((char *) &localInterface, 0, sizeof(localInterface));
int ifindex;
ifindex = if_nametoindex ("eth5");
printf ("ifindex is %d\n", ifindex);
if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)))
{
perror("Setting local interface error");
exit(1);
}
else {
printf("Setting the local interface...OK\n");
}
// choice is 0 for sending and 1 for receiving
int choice;
sscanf (argv[1], "%d", &choice);
// if sending
if (choice == 0) {
int i;
for (i = 0; i < datalen-1; ++i) {
databuf[i] = 'a';
}
databuf[i] = 0;
if (sendto(sd, databuf, datalen, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0) {
printf ("Error in send\n");
}
else {
printf ("Send okay!\n");
}
}
// if receiving
else if (choice == 1) {
groupSock.sin6_addr = in6addr_any;
if(bind(sd, (struct sockaddr*)&groupSock, sizeof(groupSock))) {
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else {
printf("Binding datagram socket...OK.\n");
}
/* Join the multicast group ff5e::/16 on the local */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
struct ipv6_mreq group;
inet_pton (AF_INET6, "ff5e::", &(group.ipv6mr_multiaddr.s6_addr));
// group.imr_interface.s6_addr = inet_addr(ip_address);
group.ipv6mr_interface = ifindex;
if(setsockopt(sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
perror("Adding multicast group error");
close(sd);
exit(1);
}
else {
printf("Adding multicast group...OK.\n");
}
if (read(sd, databuf, datalen) < 0) {
perror("Error in read");
}
else {
printf("Read Okay\n");
printf ("Message is : %s\n", databuf);
}
}
}
如果发送方和接收方在不同的节点上,则接收方收不到消息(我已使用ping6 确认它们已连接)。我正在开发 Linux Ubuntu 14.04。使用 tcpdump 捕获 ipv6 数据包显示数据包未在发送方发送。有什么问题?
一个问题是您选择的 IPv6 多播地址不当。 FF5E::
分解如下:
FF
表示多播
5
是标志集(0101
),这个值是一个无效的标志集。设置最高位意味着您有一个嵌入式 RP 地址,而您显然没有。为此,标志集必须是 7
(0111
),然后遵循嵌入 RP 地址的所有规则。
E
表示是全局作用域。
这个多播地址应该正确地丢弃在它遇到路由器的任何路径中。
请参阅 RFC 4291、3306 和 3956 以创建 IPv6 多播地址,包括标志和范围的含义。
这是发送方和接收方(组合)的代码。
int main (int argc, char *argv[]) {
struct in6_addr localInterface;
struct sockaddr_in6 groupSock;
// socket descriptor for multicast
int sd;
char databuf[10];
// length of message
int datalen = sizeof(databuf);
/* Create a datagram socket on which to send/receive. */
sd = socket(AF_INET6, SOCK_DGRAM, 0);
if(sd < 0) {
perror("Opening datagram socket error");
exit(1);
}
else {
printf("Opening the datagram socket...OK.\n");
}
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else {
printf("Setting SO_REUSEADDR...OK.\n");
}
}
/* Initialize the group sockaddr structure with a */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin6_family = AF_INET6;
// address of the group
// groupSock.sin6_addr = inet6_addr("ff5e::/16");
inet_pton(AF_INET6, "ff5e::/16", &(groupSock.sin6_addr));
groupSock.sin6_port = htons(4321);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
char *ip_address = argv[2];
inet_pton (AF_INET6, ip_address, &(localInterface.s6_addr));
memset((char *) &localInterface, 0, sizeof(localInterface));
int ifindex;
ifindex = if_nametoindex ("eth5");
printf ("ifindex is %d\n", ifindex);
if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)))
{
perror("Setting local interface error");
exit(1);
}
else {
printf("Setting the local interface...OK\n");
}
// choice is 0 for sending and 1 for receiving
int choice;
sscanf (argv[1], "%d", &choice);
// if sending
if (choice == 0) {
int i;
for (i = 0; i < datalen-1; ++i) {
databuf[i] = 'a';
}
databuf[i] = 0;
if (sendto(sd, databuf, datalen, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0) {
printf ("Error in send\n");
}
else {
printf ("Send okay!\n");
}
}
// if receiving
else if (choice == 1) {
groupSock.sin6_addr = in6addr_any;
if(bind(sd, (struct sockaddr*)&groupSock, sizeof(groupSock))) {
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else {
printf("Binding datagram socket...OK.\n");
}
/* Join the multicast group ff5e::/16 on the local */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
struct ipv6_mreq group;
inet_pton (AF_INET6, "ff5e::", &(group.ipv6mr_multiaddr.s6_addr));
// group.imr_interface.s6_addr = inet_addr(ip_address);
group.ipv6mr_interface = ifindex;
if(setsockopt(sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
perror("Adding multicast group error");
close(sd);
exit(1);
}
else {
printf("Adding multicast group...OK.\n");
}
if (read(sd, databuf, datalen) < 0) {
perror("Error in read");
}
else {
printf("Read Okay\n");
printf ("Message is : %s\n", databuf);
}
}
}
如果发送方和接收方在不同的节点上,则接收方收不到消息(我已使用ping6 确认它们已连接)。我正在开发 Linux Ubuntu 14.04。使用 tcpdump 捕获 ipv6 数据包显示数据包未在发送方发送。有什么问题?
一个问题是您选择的 IPv6 多播地址不当。 FF5E::
分解如下:
FF
表示多播5
是标志集(0101
),这个值是一个无效的标志集。设置最高位意味着您有一个嵌入式 RP 地址,而您显然没有。为此,标志集必须是7
(0111
),然后遵循嵌入 RP 地址的所有规则。E
表示是全局作用域。
这个多播地址应该正确地丢弃在它遇到路由器的任何路径中。
请参阅 RFC 4291、3306 和 3956 以创建 IPv6 多播地址,包括标志和范围的含义。