2011-03-11 33 views
5

我想編寫一個相當簡單的客戶端 - 服務器網絡應用程序。我只使用一個純粹的IPv4網絡,但這對我的代碼的未來至關重要。我可能會使用TcpListener/TcpClient,因爲preliminary investigation of WCF顯示它過於複雜,難以建立。是否有用於ipv4和ipv6地址的標準.NET解碼器?

對於客戶端來說,.NET是否提供了一種工具來自動解碼包含IPv4或IPv6地址(其中IPv4地址包含端口號)的字符串?獎勵點數,如果它可以解析一個域名。

對於服務器端,我聽到的IPv6不使用的端口號,有啥要偵聽的端口上的等效,而且是有區別從IPv6相當於IPv4端口號字符串的標準方式? 不要緊,IPv6服務具有16位端口號,就像IPv4一樣。

回答

0

正如保羅所說,沒有端口號,一個普通的IP地址可以通過IPAddress.Parse()解析。但是,如果有端口號和/或主機名(12.34.56.78:90或www.example.com:5555),則需要採用不同的方法。如果你想使用TcpClient的連接,這一功能將這樣做:

public static TcpClient Connect(string ipAndPort, int defaultPort) 
{ 
    if (ipAndPort.Contains("/")) 
     throw new FormatException("Input should only be an IP address and port"); 

    // Uri requires a prefix such as "http://", "ftp://" or even "foo://". 
    // Oddly, Uri accepts the prefix "//" UNLESS there is a port number. 
    Uri uri = new Uri("tcp://" + ipAndPort); 

    string ipOrDomain = uri.Host; 
    int port = uri.Port != -1 ? uri.Port : defaultPort; 
    return new TcpClient(ipOrDomain, port); 
} 

defaultPort參數指定如果輸入字符串沒有一個使用的端口。例如:

using (NetworkStream s = Connect("google.com", 80).GetStream()) 
{ 
    byte[] line = Encoding.UTF8.GetBytes("GET/HTTP/1.0\r\n\r\n"); 
    s.Write(line, 0, line.Length); 

    int b; 
    while ((b = s.ReadByte()) != -1) 
     Console.Write((char)b); 
} 

不用連接到它解碼地址(例如,以驗證它是有效的,或者因爲你通過,需要一個IP地址的API連接),此方法將做到這一點(和可選執行DNS查找):

public static IPAddress Resolve(string ipAndPort, ref int port, bool resolveDns) 
{ 
    if (ipAndPort.Contains("/")) 
     throw new FormatException("Input address should only contain an IP address and port"); 

    Uri uri = new Uri("tcp://" + ipAndPort); 

    if (uri.Port != -1) 
     port = uri.Port; 
    if (uri.HostNameType == UriHostNameType.IPv4 || uri.HostNameType == UriHostNameType.IPv6) 
     return IPAddress.Parse(uri.Host); 
    else if (resolveDns) 
     return Dns.GetHostAddresses(uri.Host)[0]; 
    else 
     return null; 
} 

奇怪的是,Dns.GetHostAddresses可以返回多個地址。我asked about it,顯然它可以簡單地採取第一個地址。

如果出現語法錯誤或解決域名問題(FormatExceptionSocketException),將引發異常。如果用戶指定了域名但resolveDns==false,則此方法返回null

6

沒錯System.Net.IPAddress

IPAddress.Parse("fe80::21c:42ff:fe00:8%vnic0"); 
IPAddress.Parse("127.0.0.1"); 

,並測試對IPv4或V6

if(IPAddress.Parse(...).AddressFamily == AddressFamily.InterNetwork) 
    // IPv4 address 
+0

IPAddress.Parse(「23.45.67.89:1024」)引發FormatException,所以我猜答案是「排序」。 – Qwertie 2011-03-11 19:14:50

+3

這不是一個有效的IP地址。端口號不是TCP/IP堆棧的IP部分的一部分。 IP地址沒有端口。你正在使用的是更接近於_URI_這也是與Uri類解析。 – 2011-03-11 19:28:00

+0

由於IPv6地址也包含冒號,我不知道解碼包含端口號的IPv6地址或IPv4地址的正確方法。也許可以從IPAddress.TryParse開始,如果失敗,請查找端口號,解析它,刪除它,然後重試。如果仍然失敗,請使用System.Net.Dns.Resolve作爲域名解析 - 但我很困惑,因爲它返回的IPHostEntry可以包含多個IP地址。從什麼時候一個域名有多個IP地址?我們是否應該嘗試連接所有這些? – Qwertie 2011-03-11 19:33:29

2

System.Net.IPAddress可以用來解析表示有效IPv4和IPv6地址字符串。 System.Net.Dns可用於解析網絡上的主機名和地址。

對於這兩種,

using System.Net; 
+0

你不打算提及調用哪些方法? – Qwertie 2011-03-11 19:25:31

+0

IPAddress.Parse()(或IPAddress.TryParse())和Dns.GetHostEntry() – darth10 2011-03-31 06:03:39

2

@Qwertie說:

由於IPv6地址還含有 冒號,我不知道什麼的正確方法 是解碼IPv6地址或IPv4的 地址包含一個端口號。

正如其他人所指出的,端口號不是IP地址(IPv4或IPv6)的一部分。 IP地址是原子無符號整數(IPv4是32位,IPv6是128位)。當以字符形式(例如URI)表示時,它們可以與端口號(和其他信息)組合。在URI內,主機和端口[可以]是URI的部分權限的一部分。

使用System.Uri可以將URI解析爲其組成部分。 URI的Authority部分由以下屬性組成:HostPort(以及可選的和不建議使用的UserInfo子組件,由用戶名和密碼組成)。該屬性HostNameType會告訴你你有什麼樣的主機名,enum UriHostNameType的值:Dns,Ipv4,Ipv6或其他。

您也可以解析URI到使用的RFC 3986在附錄B中定義的正則表達式的組成部分:

Appendix B. Parsing a URI Reference with a Regular Expression
As the "first-match-wins" algorithm is identical to the "greedy" disambiguation method used by POSIX regular expressions, it is natural and commonplace to use a regular expression for parsing the potential five components of a URI reference.
The following line is the regular expression for breaking-down a well-formed URI reference into its components.
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))? 12 3 4 5 6 7 8 9
The numbers in the second line above are only to assist readability; they indicate the reference points for each subexpression (i.e., each paired parenthesis). We refer to the value matched for subexpression <n> as $<n>. For example, matching the above expression to
http://www.ics.uci.edu/pub/ietf/uri/#Related
results in the following subexpression matches:
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = $7 = $8 = #Related $9 = Related
where <undefined> indicates that the component is not present, as is the case for the query component in the above example. Therefore, we can determine the value of the five components as
scheme = $2 authority = $4 path = $5 query = $7 fragment = $9
Going in the opposite direction, we can recreate a URI reference from its components by using the algorithm of Section 5.3.

不過請注意,這個正則表達式似乎稍微不正確。按照errata爲RFC 3986和它的先行詞,RFC 2396:

Errata ID: 1933
Status: Verified Type: Technical Reported By: Skip Geel Date Reported: 2009-10-25 Verifier Name: Peter Saint-Andre Date Verified: 2010-11-11
Section appendix B says:
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))?
It should say:
/^(([^:\/?#]+):)?(\/\/([^\/?#]))?([^?#])(\?([^#]))?(#(.))?/
Notes:
A Regular Expression is delimited by the slash ("/"). Within it a slash should be preceded by a back-slash ("\").
Peter: This also applies to RFC 3986.

+1

最初的正則表達式對於.NET來說看起來不錯。唯一的區別似乎是第二個版本是斜線分隔的,因此需要額外的反斜槓。 – Qwertie 2011-03-11 20:42:17

相關問題