IPv6组播不在LAN中工作

时间:2018-04-21 08:33:09

标签: c++ networking ipv6 multicast

我尝试通过网络发送IPv6组播数据包。发送似乎有效,因为它到达目标PC - 至少它出现在WireShark中记录的网络流量中。但它没有到达我的服务器程序。当我从应该接收它的同一台PC发送数据包时,它确实可以工作。

这是发送代码(删除错误检查以提高可读性):

UDPBroadcastSocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
BOOL Yes = 1;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Yes, sizeof(BOOL));
int32_t hops = 50;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&hops, sizeof(hops));
uint32_t IF = 0;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&IF, sizeof(IF));

struct sockaddr_in6 sock_in;
struct addrinfo *result = NULL;
struct addrinfo hints;

memset(&hints, 0, sizeof(hints));

hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICHOST;

getaddrinfo("FF18::1243", "12346", &hints, &result);

unsigned char buffer[MAXBUF];
int PacketSize = 8;
int sinlen = int(result->ai_addrlen);
memcpy(&sock_in, result->ai_addr, result->ai_addrlen);

freeaddrinfo(result);

sendto(UDPBroadcastSocket, (char*)buffer, PacketSize, 0, (sockaddr *)&sock_in, sinlen);

这是接收数据包的代码(删除错误检查以获得更好的可读性):

std::vector<uint32_t> GetNetworkInterfaceIndices(){
    std::vector<uint32_t> Result;

    /* Declare and initialize variables */

    DWORD dwSize = 0;
    DWORD dwRetVal = 0;

    unsigned int i = 0;

    // Set the flags to pass to GetAdaptersAddresses
    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;

    // default to unspecified address family (both)
    ULONG family = AF_UNSPEC;

    LPVOID lpMsgBuf = NULL;

    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
    ULONG outBufLen = 0;
    ULONG Iterations = 0;

    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
    PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
    PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
    IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
    IP_ADAPTER_PREFIX *pPrefix = NULL;



    family = AF_INET6;



    // Allocate a 15 KB buffer to start with.
    outBufLen = WORKING_BUFFER_SIZE;

    do {

        pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
        if (pAddresses == NULL) {
            return{ 0 };
        }

        dwRetVal =
            GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);

        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
            FREE(pAddresses);
            pAddresses = NULL;
        }
        else {
            break;
        }

        Iterations++;

    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));

    if (dwRetVal == NO_ERROR) {
        // If successful, output some information from the data we received
        pCurrAddresses = pAddresses;
        while (pCurrAddresses) {

            Result.emplace_back(pCurrAddresses->IfIndex);

            pCurrAddresses = pCurrAddresses->Next;
        }
    }
    else {

        return{ 0 };
    }

    if (pAddresses) {
        FREE(pAddresses);
    }

    return Result;
}



UDPSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);

sockaddr_in6 UDP_Sock_in;
memset(&UDP_Sock_in, 0, sizeof(sockaddr_in6));
UDP_Sock_in.sin6_addr = in6addr_any;
UDP_Sock_in.sin6_port = htons(Settings::GetPort()+1);
UDP_Sock_in.sin6_family = PF_INET6;

setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&No, sizeof(BOOL));

bind(UDPSocket, (sockaddr*)&UDP_Sock_in, sizeof(UDP_Sock_in));

ipv6_mreq BroadcastGroup;

memset(&BroadcastGroup, 0, sizeof(ipv6_mreq));

const auto IfIndices = GetNetworkInterfaceIndices();

BroadcastGroup.ipv6mr_multiaddr.u.Byte[0] = 0xFF;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[1] = 0x18;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[14] = 0x12;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[15] = 0x43;

for (const auto& Index : IfIndices) {
    BroadcastGroup.ipv6mr_interface = Index;
    setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&BroadcastGroup, sizeof(ipv6_mreq));        
} 



socklen_t fromLength = sizeof(sockaddr_in6);

pollfd PollFd;
PollFd.events = POLLIN;
PollFd.fd = UDPSocket;
PollFd.revents = -1;

WSAPoll(&PollFd, 1, -1);

recvfrom(UDPSocket, (char*)buffer, MAXBUF, 0, (sockaddr*)&from, &fromLength);

我基本上尝试指定每个网络接口索引,但数据包仍未到达服务器。我不知道会出现什么问题。当发送者和接收者在同一台PC上时,为什么它可以工作?我不明白这一点。有没有人有想法?它不是防火墙,我把它关掉了,没有任何改变。当我直接指定接收PC的IP地址时,它也可以正常工作。

1 个答案:

答案 0 :(得分:-2)

我找到了一种解决方法:只需切换到IPv4,因为IPv6多播目前似乎无法在Windows上运行(至少在我的用例中,请参阅注释)。我的代码已经运行了,但是前一段时间停止工作,直到我再次测试它才发现。

我尝试了一堆不同的地址,显然它们都没有在3种不同的设备上运行。然后我切换到IPv4,它只是工作 - 我只将IPv6相关的东西改为他们的IPv4等价物,并删除了发送者的跳跃和界面选项。

我的接收器甚至出现在多播组列表中(您可以使用命令&#34; netsh interface ipv6 show joins&#34;)看到,但仍然没有收到发送到其地址的数据包,所以我得出结论,它可能是一个错误,因为我找到的每个示例代码都不适合我,我找不到任何其他我可能错过的setsockopt选项。如果您知道可能导致此问题的原因或如何修复它而不切换回旧的IPv4标准,请随时发表评论。