Puisque IPEndpoint
contient une méthode ToString()
qui génère:
10.10.10.10:1010
Il devrait également y avoir une méthode Parse()
et/ou TryParse()
mais il n'y en a pas.
Je peux diviser la chaîne sur le :
et analyser une adresse IP et un port.
Mais y a-t-il un moyen plus élégant?
C'est une solution ...
public static IPEndPoint CreateIPEndPoint(string endPoint)
{
string[] ep = endPoint.Split(':');
if(ep.Length != 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if(!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid ip-adress");
}
int port;
if(!int.TryParse(ep[1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
Edit: Ajout d'une version qui gérera IPv4 et IPv6, la précédente ne gérera que IPv4.
// Handles IPv4 and IPv6 notation.
public static IPEndPoint CreateIPEndPoint(string endPoint)
{
string[] ep = endPoint.Split(':');
if (ep.Length < 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if (ep.Length > 2)
{
if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
else
{
if (!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
int port;
if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
J'avais l'exigence d'analyser un IPEndpoint avec IPv6, v4 et noms d'hôtes. La solution que j'ai écrite est listée ci-dessous:
public static IPEndPoint Parse(string endpointstring)
{
return Parse(endpointstring, -1);
}
public static IPEndPoint Parse(string endpointstring, int defaultport)
{
if (string.IsNullOrEmpty(endpointstring)
|| endpointstring.Trim().Length == 0)
{
throw new ArgumentException("Endpoint descriptor may not be empty.");
}
if (defaultport != -1 &&
(defaultport < IPEndPoint.MinPort
|| defaultport > IPEndPoint.MaxPort))
{
throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport));
}
string[] values = endpointstring.Split(new char[] { ':' });
IPAddress ipaddy;
int port = -1;
//check if we have an IPv6 or ports
if (values.Length <= 2) // ipv4 or hostname
{
if (values.Length == 1)
//no port is specified, default
port = defaultport;
else
port = getPort(values[1]);
//try to use the address as IPv4, otherwise get hostname
if (!IPAddress.TryParse(values[0], out ipaddy))
ipaddy = getIPfromHost(values[0]);
}
else if (values.Length > 2) //ipv6
{
//could [a:b:c]:d
if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
{
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
ipaddy = IPAddress.Parse(ipaddressstring);
port = getPort(values[values.Length - 1]);
}
else //[a:b:c] or a:b:c
{
ipaddy = IPAddress.Parse(endpointstring);
port = defaultport;
}
}
else
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
}
if (port == -1)
throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring));
return new IPEndPoint(ipaddy, port);
}
private static int getPort(string p)
{
int port;
if (!int.TryParse(p, out port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
}
return port;
}
private static IPAddress getIPfromHost(string p)
{
var hosts = Dns.GetHostAddresses(p);
if (hosts == null || hosts.Length == 0)
throw new ArgumentException(string.Format("Host not found: {0}", p));
return hosts[0];
}
Cela a été testé pour fonctionner avec les exemples suivants:
Il semble qu'il existe déjà une méthode intégrée dans Parse qui gère les adresses ip4 et ip6 http://msdn.Microsoft.com/en-us/library/system.net.ipaddress.parse%28v=vs. 110% 29.aspx
// serverIP can be in ip4 or ip6 format
string serverIP = "192.168.0.1";
string port = 8000;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(serverIP), port);
Voici ma version de l'analyse du texte à IPEndPoint
:
private static IPEndPoint ParseIPEndPoint(string text)
{
Uri uri;
if (Uri.TryCreate(text, UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
if (Uri.TryCreate(String.Concat("tcp://", text), UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
if (Uri.TryCreate(String.Concat("tcp://", String.Concat("[", text, "]")), UriKind.Absolute, out uri))
return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port);
throw new FormatException("Failed to parse text to IPEndPoint");
}
Testé avec:
Cela fera IPv4 et IPv6. Une méthode d'extension pour cette fonctionnalité serait sur System.string. Pas sûr que je veuille cette option pour chaque chaîne que j'ai dans le projet.
private static IPEndPoint IPEndPointParse(string endpointstring)
{
string[] values = endpointstring.Split(new char[] {':'});
if (2 > values.Length)
{
throw new FormatException("Invalid endpoint format");
}
IPAddress ipaddress;
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
if (!IPAddress.TryParse(ipaddressstring, out ipaddress))
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", ipaddressstring));
}
int port;
if (!int.TryParse(values[values.Length - 1], out port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", values[values.Length - 1]));
}
return new IPEndPoint(ipaddress, port);
}
Si le numéro de port est toujours fourni après un ':'
, la méthode suivante peut constituer une option plus élégante (longueur du code au lieu de l'efficacité).
public static IPEndpoint ParseIPEndpoint(string ipEndPoint) {
int ipAddressLength = ipEndPoint.LastIndexOf(':');
return new IPEndPoint(
IPAddress.Parse(ipEndPoint.Substring(0, ipAddressLength)),
Convert.ToInt32(ipEndPoint.Substring(ipAddressLength + 1)));
}
Cela fonctionne bien pour mon application simple sans tenir compte du format d'adresse IP complexe.
Ceci est mon point de vue sur l'analyse d'un IPEndPoint. L'utilisation de la classe Uri évite d'avoir à gérer les spécificités d'IPv4/6, et la présence ou non du port. Vous pouvez modifier le port par défaut de votre application.
public static bool TryParseEndPoint(string ipPort, out System.Net.IPEndPoint result)
{
result = null;
string scheme = "iiiiiiiiiaigaig";
GenericUriParserOptions options =
GenericUriParserOptions.AllowEmptyAuthority |
GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoFragment |
GenericUriParserOptions.DontCompressPath |
GenericUriParserOptions.DontConvertPathBackslashes |
GenericUriParserOptions.DontUnescapePathDotsAndSlashes;
UriParser.Register(new GenericUriParser(options), scheme, 1337);
Uri parsedUri;
if (!Uri.TryCreate(scheme + "://" + ipPort, UriKind.Absolute, out parsedUri))
return false;
System.Net.IPAddress parsedIP;
if (!System.Net.IPAddress.TryParse(parsedUri.Host, out parsedIP))
return false;
result = new System.Net.IPEndPoint(parsedIP, parsedUri.Port);
return true;
}
Le code d'analyse est simple pour un point de terminaison IPv4, mais IPEndPoint.ToString () sur une adresse IPv6 utilise également la même notation deux points, mais est en conflit avec la notation deux points de l'adresse IPv6. J'espérais que Microsoft passerait l'effort à écrire ce code d'analyse moche à la place, mais je suppose que je devrai ...
Créez une méthode d'extension Parse et TryParse. Je suppose que c'est plus élégant.
Apparemment, IPEndPoint.Parse
et IPEndPoint.TryParse
ont récemment ajouté } à .NET Core 3.0.
Si vous le ciblez, essayez ces méthodes! La mise en œuvre est visible dans le lien ci-dessus.
Voici une solution très simple, il gère à la fois IPv4 et IPv6.
public class IPEndPoint : System.Net.IPEndPoint
{
public IPEndPoint(long address, int port) : base(address, port) { }
public IPEndPoint(IPAddress address, int port) : base(address, port) { }
public static bool TryParse(string value, out IPEndPoint result)
{
if (!Uri.TryCreate($"tcp://{value}", UriKind.Absolute, out Uri uri) ||
!IPAddress.TryParse(uri.Host, out IPAddress ipAddress) ||
uri.Port < 0 || uri.Port > 65535)
{
result = default(IPEndPoint);
return false;
}
result = new IPEndPoint(ipAddress, uri.Port);
return true;
}
}
Utilisez simplement le TryParse
comme vous le feriez normalement.
IPEndPoint.TryParse("192.168.1.10:80", out IPEndPoint ipv4Result);
IPEndPoint.TryParse("[fd00::]:8080", out IPEndPoint ipv6Result);