2011-09-08 52 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*/);