我在C#应用程序中使用IGMPv3来支持此行为。 Here is how I do it.
我现在正在申请中添加对IPv6的支持,我需要获得与IPv4相同的行为。根据我的阅读,IPv6中与IGMPv3等效的协议是MLDv2。有人知道如何用Cocket实现这个吗?
谢谢!
答案 0 :(得分:1)
RFC3678协议独立API仅适用于Vista +,可解释此问题。
如果C#运行时完全支持IPv6,则必须尝试匹配GROUP_REQ或GROUP_SOURCE_REQ结构。 SSM没有与IPv6 API匹配的IPv6特定API,因为开发人员最终放弃了API的无聊复制,最终确定了一个超级集。
很遗憾,C#为AddMembership
实现ipv6_mreq并且AddSourceMembership
失败。文档完全没有详细说明。
所需的所有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
答案 1 :(得分:0)
为了跟进Steve-o的答案,即使System.Net.Sockets.SocketOptionName枚举没有通过转换数字来定义所需的选项,仍然可以在C#中使用IPv6进行源过滤直接
(SocketOptionName) 45; //MCAST_JOIN_SOURCE_GROUP
套接字的函数SetSocketOption将让调用转到" windows socket"即使该选项未被识别。真正的斗争变成了数据结构本身,需要与选项一起发送。 要设置源过滤,数据结构必须与此类似:group_source_req。之前的结构使用的sockaddr_storage通常位于与sockaddr_in和sockaddr_in6结合的联盟中。要复制此行为,我们可以定义相同的结构:
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];
}
现在可以使用提供的解决方案here提取sockaddr_in6的字节,并将其直接复制到先前创建的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];
}
现在您有了一个sockaddr_storage,您可以将它分配给group_source_req并像之前一样提取group_source_req的数据,并在设置选项时将其用作值。
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName) 45, /*data extracted from group_source_req*/);