2011-09-08 27 views
0


在IPv4中,Version 3 of IGMP adds support for "source filtering", that is, the ability for a system to report interest in receiving packets only from specific source addresses.如何在C#(IPv6组播)

我使用的IGMPv3在C#应用程序以支持此行为使用MLDv2的。 Here is how I do it.

我现在正在向我的应用程序添加对IPv6的支持,我需要获得与IPv4中相同的行为。从我读到的,IPv6中IGMPv3的等效协议是MLDv2。有人有关于如何在C#中使用Socket实现这个想法吗?

谢谢!

回答

1

RFC3678独立于协议的API仅在Vista +中可用,这可能会解释问题。

如果C#运行时完全支持IPv6,则必须尝试匹配GROUP_REQGROUP_SOURCE_REQ结构。由于开发人员最终放弃了API的重复复制并最终选定了一个超集,因此没有针对SSM匹配IPv4 API的IPv6特定API。

不幸的是,C#实现ipv6_mreqAddMembershipAddSourceMembership失败。文档完全没有详细说明。

所有所需的SocketOptionName值在C#中没有定义:

/* RFC 3678 */ 
#define MCAST_JOIN_GROUP  41 
#define MCAST_LEAVE_GROUP  42 
#define MCAST_BLOCK_SOURCE  43 
#define MCAST_UNBLOCK_SOURCE 44 
#define MCAST_JOIN_SOURCE_GROUP  45 
#define MCAST_LEAVE_SOURCE_GROUP  46 
#define MCAST_MSFILTER   47 
+0

感谢您的回答。对于没有特定源的IPv6多播,我能够匹配GROUP_REQ结构并在设置套接字选项时使用AddMembership(另一种选择是使用IPv6MulticastOption),但对GROUP_SOURCE_REQ和AddSourceMembership做同样的事情只是保持抛出异常。 – Absolom

0

要在史蒂夫 - O的答案跟进,它仍然是可以做到的源过滤在IPv6中在C#中,即使系统。 Net.Sockets.SocketOptionName枚举不通过直接转换数字来定义所需的选项。

(SocketOptionName) 45; //MCAST_JOIN_SOURCE_GROUP 

即使该选项未被识别,套接字的函数SetSocketOption也会让调用进入“窗口套接字”。真正的斗争成为需要随选项一起发送的数据结构本身。 要设置源过滤,数据结构必须如下所示:group_source_req。前面的结构使用通常在sockaddr_insockaddr_in6的联合中的sockaddr_storage。要复制这种行为,我们可以定义相同的结构是这样的:

private unsafe struct sockaddr_storage 
{ 
    public short ss_family;    //2 
    private fixed byte __ss_pad1[6]; //6 
    private Int64 __ss_align;   //8 
    private fixed byte __ss_pad2[112]; //112 
} 
private unsafe struct sockaddr_in 
{ 
    public ushort sin_family;  //2 
    public ushort sin_port;   //2 
    public fixed byte sin_addr[4]; //4 
    private fixed byte sub_zero[8]; //8 
} 
private unsafe struct sockaddr_in6 
{ 
    public ushort sin6_family;  //2 
    public ushort sin6_port;   //2 
    public int sin6_flowinfo;  //4 
    public fixed byte sin6_addr[16]; //16 
    public uint sin6_scope_id;  //4 
} 
private struct group_source_req 
{ 
    public uint gr_interface;   //4 
    //Compiler add a padding here:  //4 
    public sockaddr_storage gr_group; //128 
    public sockaddr_storage gr_source; //128 
} 

您可以通过这样做,现在创建一个sockaddr_in6的:

sockaddr_in6 sockIn = new sockaddr_in6 
{ 
    sin6_family = (ushort) endPoint.AddressFamily, 
    sin6_port = (ushort)endPoint.Port, 
    sin6_scope_id = 0 
}; 
for (int i = 0; i < endPoint.Address.GetAddressBytes().Length; i++) 
{ 
    sockIn.sin6_addr[i] = endPoint.Address.GetAddressBytes()[i]; 
} 

的sockaddr_in6的的字节现在可以通过使用该解决方案中提取提供here和直接复制到以前创建的struct sockaddr_storage的:

sockaddr_storage sock = new sockaddr_storage 
{ 
    ss_family = (short)endPoint.AddressFamily 
}; 
//[...] 
byte[] sockInData = getBytes(sockIn); 
byte* sockData = (byte*) &sock; 
for (int i = 0; i < sockInData.Length; i++) 
{ 
    sockData [i] = sockInData[i]; 
} 

现在,你有一个struct sockaddr_storage的,你可以把它分配给group_s ource_req并像我们之前所做的那样提取group_source_req的数据,并在设置选项时使用它作为值。

socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName) 45, /*data extracted from group_source_req*/);