Существует ли стандартный декодер .NET для адресов ipv4 и ipv6? - PullRequest
5 голосов
/ 11 марта 2011

Я хотел бы написать довольно простое клиент-серверное сетевое приложение.Я использую только чистую сеть IPv4, но было бы неплохо, чтобы мой код был на будущее.Я, вероятно, буду использовать TcpListener / TcpClient, потому что предварительное исследование WCF показывает, что его слишком сложно настроить и трудно взломать.

Для клиентской стороны .NET предоставляетсредство для автоматического декодирования строки, содержащей адрес IPv4 или IPv6 (где адрес IPv4 включает номер порта)?Бонусные баллы, если он может разрешить доменное имя.

Что касается серверной части, я слышал, что IPv6 не использует номера портов, так что это эквивалент порта для прослушивания, и есть ли стандартспособ отличить строку номера порта IPv4 от эквивалента IPv6? Не берите в голову, сервисы IPv6 имеют 16-битные номера портов, как и IPv4.

Ответы [ 4 ]

6 голосов
/ 11 марта 2011

Да 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
2 голосов
/ 11 марта 2011

@ Qwertie сказал:

Поскольку адреса IPv6 также содержат двоеточия, мне интересно, как правильно декодировать адрес IPv6 или адрес IPv4, содержащий номер порта.

Как уже отмечали другие, номер порта не является частью IP-адреса (IPv4 или IPv6).IP-адреса являются атомарными целыми числами без знака (IPv4 является 32-разрядным, IPv6 является 128-разрядным).Когда они представлены в символьной форме (такой как URI), они могут быть объединены с номером порта (и другой информацией).Внутри URI хост и порт [могут быть] частью полномочий части URI.

URI могут быть проанализированы в составные части с помощью System.Uri.Часть Authority URI состоит из следующих свойств: Host, Port (и, необязательно, не рекомендуется, подкомпонента UserInfo, состоящего из имени пользователя и пароля).Свойство HostNameType сообщит вам, какое у вас имя хоста, значение перечисления UriHostNameType: Dns, Ipv4, Ipv6 или что-то еще.

Вы также можете проанализировать URI в его компоненте.части, использующие регулярное выражение, определенное в Приложении B к RFC 3986 :

Appendix B.  Parsing a URI Reference with a Regular Expression<br/>
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.<br/>
The following line is the regular expression for breaking-down a
well-formed URI reference into its components.<br/>
  ^(([^:/?#]+):)?(//([^/?#]<em>))?([^?#]</em>)(\?([^#]<em>))?(#(.</em>))?
   12            3  4          5       6  7        8 9
<br/>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<br/>
  <a href="http://www.ics.uci.edu/pub/ietf/uri/#Related" rel="nofollow">http://www.ics.uci.edu/pub/ietf/uri/#Related</a><br/>
results in the following subexpression matches:<br/>
  $1 = http:
  $2 = http
  $3 = //www.ics.uci.edu
  $4 = www.ics.uci.edu
  $5 = /pub/ietf/uri/
  $6 = 
  $7 = 
  $8 = #Related
  $9 = Related<br/>
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<br/>
  scheme    = $2
  authority = $4
  path      = $5
  query     = $7
  fragment  = $9<br/>
Going in the opposite direction, we can recreate a URI reference from
its components by using the algorithm of Section 5.3.

Обратите внимание, что это регулярное выражение кажется слегка некорректным.Согласно ошибкам для RFC 3986 и его предшественнику, RFC 2396:

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

System.Net.IPAddress может использоваться для анализа строк, представляющих действительные адреса IPv4 и IPv6.System.Net.Dns можно использовать для разрешения имен хостов и адресов в сети.

Для обоих

using System.Net;
0 голосов
/ 12 марта 2011

Как упоминал Пол, простой 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);
}

Чтобы декодировать адрес без подключения к нему (например, чтобы убедиться, что он действителен или вы подключаетесь через API, для которого требуется IP-адрес), этот метод будет делать это (и при необходимости выполнить поиск 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 может возвращать несколько адресов.Я спросил об этом , и, видимо, можно просто взять первый адрес.

Исключение будет возникать в случае синтаксической ошибки или проблемы с разрешением имени домена (FormatExceptionили SocketException).Если пользователь указал доменное имя, но resolveDns==false, этот метод возвращает null.

...