Since IPEndpoint
contains a ToString()
method that outputs:
10.10.10.10:1010
There should also be
This will do IPv4 and IPv6. An extension method for this functionality would be on System.string. Not sure I want this option for every string I have in the project.
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);
}
Apparently, IPEndPoint.Parse
and IPEndPoint.TryParse
were added in .NET Core 3.0.
In case you're targeting it, give those methods a try! The implementation is seen in the link above.
I had the requirement of parsing an IPEndpoint with IPv6, v4 and hostnames. The solution I wrote is listed below:
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];
}
This has been tested to work with the following examples:
Here is my version of parsing text to 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");
}
Tested with:
If the port number is always provided after a ':'
, the following method may be a more elegant option (in code length instead of efficiency).
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)));
}
It works fine for my simple application without considering complex IP address format.
The parsing code is simple for an IPv4 endpoint, but IPEndPoint.ToString() on an IPv6 address also uses the same colon notation, but conflicts with the IPv6 address's colon notation. I was hoping Microsoft would spend the effort writing this ugly parsing code instead, but I guess I'll have to...