[英]Get public/external IP address?
我似乎無法獲取或找到有關查找我的路由器公共 IP 的信息? 這是因為它不能以這種方式完成並且必須從網站上獲取它嗎?
使用 C#,使用 webclient 它是一個簡短的。
public static void Main(string[] args)
{
string externalIpString = new WebClient().DownloadString("http://icanhazip.com").Replace("\\r\\n", "").Replace("\\n", "").Trim();
var externalIp = IPAddress.Parse(externalIpString);
Console.WriteLine(externalIp.ToString());
}
命令行(適用於 Linux 和 Windows)
wget -qO- http://bot.whatismyipaddress.com
或者
curl http://ipinfo.io/ip
static void Main(string[] args)
{
HTTPGet req = new HTTPGet();
req.Request("http://checkip.dyndns.org");
string[] a = req.ResponseBody.Split(':');
string a2 = a[1].Substring(1);
string[] a3=a2.Split('<');
string a4 = a3[0];
Console.WriteLine(a4);
Console.ReadLine();
}
用檢查 IP DNS做這個小技巧
使用我在Goldb-Httpget C#上找到的HTTPGet
類
使用 .Net WebRequest:
public static string GetPublicIP()
{
string url = "http://checkip.dyndns.org";
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
System.Net.WebResponse resp = req.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
string response = sr.ReadToEnd().Trim();
string[] a = response.Split(':');
string a2 = a[1].Substring(1);
string[] a3 = a2.Split('<');
string a4 = a3[0];
return a4;
}
string pubIp = new System.Net.WebClient().DownloadString("https://api.ipify.org");
使用很棒的類似服務
private string GetPublicIpAddress()
{
var request = (HttpWebRequest)WebRequest.Create("http://ifconfig.me");
request.UserAgent = "curl"; // this will tell the server to return the information as if the request was made by the linux "curl" command
string publicIPAddress;
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
publicIPAddress = reader.ReadToEnd();
}
}
return publicIPAddress.Replace("\n", "");
}
由@ suneel ranga擴展此答案:
static System.Net.IPAddress GetPublicIp(string serviceUrl = "https://ipinfo.io/ip")
{
return System.Net.IPAddress.Parse(new System.Net.WebClient().DownloadString(serviceUrl));
}
您將在其中使用System.Net.WebClient
服務,該服務僅將 IP 地址顯示為字符串並使用System.Net.IPAddress
對象。 以下是一些此類服務*:
* 這個問題和超級用戶站點的這些答案中提到了一些服務。
從理論上講,您的路由器應該能夠告訴您網絡的公共 IP 地址,但是這樣做的方式必然是不一致/不直接的,即使對於某些路由器設備也是如此。
最簡單且仍然非常可靠的方法是向網頁發送請求,該網頁在 Web 服務器看到時返回您的 IP 地址。 Dyndns.org 為此提供了很好的服務:
返回的是一個非常簡單/簡短的 HTML 文檔,其中包含文本Current IP Address: 157.221.82.39
(fake IP),從 HTTP 響應中提取它是微不足道的。
我發現http://checkip.dyndns.org/給了我必須處理的 html 標簽,但https://icanhazip.com/只是給了我一個簡單的字符串。 不幸的是https://icanhazip.com/給了我 ip6 地址,我需要 ip4。 幸運的是,您可以選擇 2 個子域,ipv4.icanhazip.com 和 ipv6.icanhazip.com。
string externalip = new WebClient().DownloadString("https://ipv4.icanhazip.com/");
Console.WriteLine(externalip);
Console.WriteLine(externalip.TrimEnd());
只需幾行代碼,您就可以為此編寫自己的 Http Server。
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://+/PublicIP/");
listener.Start();
while (true)
{
HttpListenerContext context = listener.GetContext();
string clientIP = context.Request.RemoteEndPoint.Address.ToString();
using (Stream response = context.Response.OutputStream)
using (StreamWriter writer = new StreamWriter(response))
writer.Write(clientIP);
context.Response.Close();
}
然后,任何時候你需要知道你的公共 IP,你都可以這樣做。
WebClient client = new WebClient();
string ip = client.DownloadString("http://serverIp/PublicIP");
基本上我更喜歡使用一些額外的備份,以防其中一個 IP 不可訪問。 所以我使用這種方法。
public static string GetExternalIPAddress()
{
string result = string.Empty;
try
{
using (var client = new WebClient())
{
client.Headers["User-Agent"] =
"Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) " +
"(compatible; MSIE 6.0; Windows NT 5.1; " +
".NET CLR 1.1.4322; .NET CLR 2.0.50727)";
try
{
byte[] arr = client.DownloadData("http://checkip.amazonaws.com/");
string response = System.Text.Encoding.UTF8.GetString(arr);
result = response.Trim();
}
catch (WebException)
{
}
}
}
catch
{
}
if (string.IsNullOrEmpty(result))
{
try
{
result = new WebClient().DownloadString("https://ipinfo.io/ip").Replace("\n", "");
}
catch
{
}
}
if (string.IsNullOrEmpty(result))
{
try
{
result = new WebClient().DownloadString("https://api.ipify.org").Replace("\n", "");
}
catch
{
}
}
if (string.IsNullOrEmpty(result))
{
try
{
result = new WebClient().DownloadString("https://icanhazip.com").Replace("\n", "");
}
catch
{
}
}
if (string.IsNullOrEmpty(result))
{
try
{
result = new WebClient().DownloadString("https://wtfismyip.com/text").Replace("\n", "");
}
catch
{
}
}
if (string.IsNullOrEmpty(result))
{
try
{
result = new WebClient().DownloadString("http://bot.whatismyipaddress.com/").Replace("\n", "");
}
catch
{
}
}
if (string.IsNullOrEmpty(result))
{
try
{
string url = "http://checkip.dyndns.org";
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
System.Net.WebResponse resp = req.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
string response = sr.ReadToEnd().Trim();
string[] a = response.Split(':');
string a2 = a[1].Substring(1);
string[] a3 = a2.Split('<');
result = a3[0];
}
catch (Exception)
{
}
}
return result;
}
為了更新 GUI 控件(WPF、.NET 4.5),例如我使用此代碼的一些標簽
void GetPublicIPAddress()
{
Task.Factory.StartNew(() =>
{
var ipAddress = SystemHelper.GetExternalIPAddress();
Action bindData = () =>
{
if (!string.IsNullOrEmpty(ipAddress))
labelMainContent.Content = "IP External: " + ipAddress;
else
labelMainContent.Content = "IP External: ";
labelMainContent.Visibility = Visibility.Visible;
};
this.Dispatcher.InvokeAsync(bindData);
});
}
希望它是有用的。
這是一個包含此代碼的應用程序示例。
無需任何連接即可快速獲取外部 ip 實際上不需要任何 Http 連接
首先你必須在引用上添加 NATUPNPLib.dll 並從引用中選擇它並從屬性窗口中檢查 Embed Interop Type to False
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NATUPNPLib; // Add this dll from referance and chande Embed Interop Interop to false from properties panel on visual studio
using System.Net;
namespace Client
{
class NATTRAVERSAL
{
//This is code for get external ip
private void NAT_TRAVERSAL_ACT()
{
UPnPNATClass uPnP = new UPnPNATClass();
IStaticPortMappingCollection map = uPnP.StaticPortMappingCollection;
foreach (IStaticPortMapping item in map)
{
Debug.Print(item.ExternalIPAddress); //This line will give you external ip as string
break;
}
}
}
}
checkip.dyndns.org 並不總是正常工作。 例如,對於我的機器,它顯示內部 NAT 后地址:
Current IP Address: 192.168.1.120
我認為它正在發生,因為我在 NAT 后面有我的本地 DNS 區域,並且我的瀏覽器發送到 checkip 其本地 IP 地址,該地址被返回。
此外,http 是重量級的、面向文本的基於 TCP 的協議,因此不太適合快速高效地定期請求外部 IP 地址。 我建議使用基於 UDP 的二進制 STUN,特別為此目的而設計:
http://en.wikipedia.org/wiki/STUN
STUN-server 就像“UDP 鏡像”。 你看着它,看看“我的樣子”。
世界上有許多公共 STUN 服務器,您可以在其中請求您的外部 IP。 例如,請參見此處:
http://www.voip-info.org/wiki/view/STUN
您可以從 Internet 下載任何 STUN 客戶端庫,例如,這里:
http://www.codeproject.com/Articles/18492/STUN-Client
並使用它。
private static string GetPublicIpAddress()
{
using (var client = new WebClient())
{
return client.DownloadString("http://ifconfig.me").Replace("\n", "");
}
}
我發現大多數其他答案都缺乏,因為他們假設任何返回的字符串都必須是 IP,但並沒有真正檢查它。 這是我目前正在使用的解決方案。 如果沒有找到,它只會返回一個有效的 IP 或 null。
public class WhatsMyIp
{
public static IPAddress PublicIp { get; private set; }
static WhatsMyIp()
{
PublicIp = GetMyIp();
}
public static IPAddress GetMyIp()
{
List<string> services = new List<string>()
{
"https://ipv4.icanhazip.com",
"https://api.ipify.org",
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com",
"https://wtfismyip.com/text",
"http://icanhazip.com"
};
using (var webclient = new WebClient())
foreach (var service in services)
{
try { return IPAddress.Parse(webclient.DownloadString(service)); } catch { }
}
return null;
}
}
當我調試時,我使用以下來構造外部可調用的 URL,但您可以只使用前 2 行來獲取您的公共 IP:
public static string ExternalAction(this UrlHelper helper, string actionName, string controllerName = null, RouteValueDictionary routeValues = null, string protocol = null)
{
#if DEBUG
var client = new HttpClient();
var ipAddress = client.GetStringAsync("http://ipecho.net/plain").Result;
// above 2 lines should do it..
var route = UrlHelper.GenerateUrl(null, actionName, controllerName, routeValues, helper.RouteCollection, helper.RequestContext, true);
if (route == null)
{
return route;
}
if (string.IsNullOrEmpty(protocol) && string.IsNullOrEmpty(ipAddress))
{
return route;
}
var url = HttpContext.Current.Request.Url;
protocol = !string.IsNullOrWhiteSpace(protocol) ? protocol : Uri.UriSchemeHttp;
return string.Concat(protocol, Uri.SchemeDelimiter, ipAddress, route);
#else
helper.Action(action, null, null, HttpContext.Current.Request.Url.Scheme)
#endif
}
我使用System.Net.Http
中的HttpClient
來做到這一點:
public static string PublicIPAddress()
{
string uri = "http://checkip.dyndns.org/";
string ip = String.Empty;
using (var client = new HttpClient())
{
var result = client.GetAsync(uri).Result.Content.ReadAsStringAsync().Result;
ip = result.Split(':')[1].Split('<')[0];
}
return ip;
}
基於使用外部 Web 服務的答案並不完全正確,因為它們實際上並未回答所述問題:
...有關查找我的路由器公共 IP 的信息
解釋
所有在線服務都返回外部 IP 地址,但這並不意味着該地址已分配給用戶的路由器。
路由器可能被分配了 ISP 基礎設施網絡的另一個本地 IP 地址。 實際上,這意味着該路由器不能托管 Internet 上可用的任何服務。 這可能對大多數家庭用戶的安全有利,但對在家托管服務器的極客不利。
以下是檢查路由器是否有外部IP的方法:
根據Wikipedia文章,IP 地址范圍10.0.0.0 – 10.255.255.255
、 172.16.0.0 – 172.31.255.255
和192.168.0.0 – 192.168.255.255
用於私有即本地網絡。
看看當您使用分配有外部 IP 地址的路由器跟蹤到某個遠程主機的路由時會發生什么:
明白了! 第一跳現在從31.*
開始。 這顯然意味着您的路由器和 Internet 之間沒有任何關系。
解決方案
Ttl = 2
對某個地址進行 Ping TTL=2 必須不足以到達遠程主機。 躍點 #1 主機將發出"Reply from <ip address>: TTL expired in transit."
透露其IP地址。
執行
try
{
using (var ping = new Ping())
{
var pingResult = ping.Send("google.com");
if (pingResult?.Status == IPStatus.Success)
{
pingResult = ping.Send(pingResult.Address, 3000, "ping".ToAsciiBytes(), new PingOptions { Ttl = 2 });
var isRealIp = !Helpers.IsLocalIp(pingResult?.Address);
Console.WriteLine(pingResult?.Address == null
? $"Has {(isRealIp ? string.Empty : "no ")}real IP, status: {pingResult?.Status}"
: $"Has {(isRealIp ? string.Empty : "no ")}real IP, response from: {pingResult.Address}, status: {pingResult.Status}");
Console.WriteLine($"ISP assigned REAL EXTERNAL IP to your router, response from: {pingResult?.Address}, status: {pingResult?.Status}");
}
else
{
Console.WriteLine($"Your router appears to be behind ISP networks, response from: {pingResult?.Address}, status: {pingResult?.Status}");
}
}
}
catch (Exception exc)
{
Console.WriteLine("Failed to resolve external ip address by ping");
}
小助手用於檢查 IP 是屬於私有網絡還是公共網絡:
public static bool IsLocalIp(IPAddress ip) {
var ipParts = ip.ToString().Split(new [] { "." }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
return (ipParts[0] == 192 && ipParts[1] == 168)
|| (ipParts[0] == 172 && ipParts[1] >= 16 && ipParts[1] <= 31)
|| ipParts[0] == 10;
}
我找到的最佳答案
以最快的方式獲取遠程 IP 地址。 您必須使用下載器,或在您的計算機上創建服務器。
使用這個簡單代碼的缺點:(推薦)是獲取遠程 IP 地址需要 3-5 秒,因為初始化時 WebClient 總是需要 3-5 秒來檢查您的代理設置。
public static string GetIP()
{
string externalIP = "";
externalIP = new WebClient().DownloadString("http://checkip.dyndns.org/");
externalIP = (new Regex(@"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"))
.Matches(externalIP)[0].ToString();
return externalIP;
}
這是我修復它的方法..(第一次仍然需要 3-5 秒)但之后它總是會在 0-2 秒內獲得您的遠程 IP 地址,具體取決於您的連接。
public static WebClient webclient = new WebClient();
public static string GetIP()
{
string externalIP = "";
externalIP = webclient.DownloadString("http://checkip.dyndns.org/");
externalIP = (new Regex(@"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"))
.Matches(externalIP)[0].ToString();
return externalIP;
}
我重構了@Academy of Programmer 對更短代碼的回答並對其進行了更改,使其僅訪問https://
URL:
public static string GetExternalIPAddress()
{
string result = string.Empty;
string[] checkIPUrl =
{
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com/",
"https://api.ipify.org",
"https://icanhazip.com",
"https://wtfismyip.com/text"
};
using (var client = new WebClient())
{
client.Headers["User-Agent"] = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) " +
"(compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
foreach (var url in checkIPUrl)
{
try
{
result = client.DownloadString(url);
}
catch
{
}
if (!string.IsNullOrEmpty(result))
break;
}
}
return result.Replace("\n", "").Trim();
}
}
您可以使用Telnet以編程方式查詢路由器的 WAN IP。
Telnet 部分
Telnet 部分可以使用例如這個 Minimalistic Telnet 代碼作為 API 來完成,以向您的路由器發送 Telnet 命令並獲得路由器的響應。 此答案的其余部分假設您以一種或另一種方式設置為發送 Telnet 命令並在代碼中取回響應。
方法的局限性
我會提前說,與其他方法相比,查詢路由器的一個缺點是您編寫的代碼可能相當特定於您的路由器模型。 也就是說,它可能是一種不依賴外部服務器的有用方法,並且您可能希望從您自己的軟件訪問您的路由器以用於其他目的,例如配置和控制它,使其更值得編寫特定代碼。
示例路由器命令和響應
下面的示例並不適用於所有路由器,但原則上說明了該方法。 您將需要更改詳細信息以適合您的路由器命令和響應。
例如,讓路由器顯示 WAN IP 的方法可能是以下 Telnet 命令:
connection list
輸出可能包含一個文本行列表,每個連接一個,IP 地址在偏移量 39 處。WAN 連接的行可以從該行某處的單詞“Internet”中識別:
RESP: 3947 17.110.226. 13:443 146.200.253. 16:60642 [R..A] Internet 6 tcp 128
<------------------ 39 -------------><-- WAN IP -->
輸出可能會將每個 IP 地址段填充為三個帶有空格的字符,您需要將其刪除。 (也就是說,在上面的示例中,您需要將“146.200.253.16”轉換為“146.200.253.16”。)
通過試驗或查閱路由器的參考文檔,您可以建立用於特定路由器的命令以及如何解釋路由器的響應。
獲取WAN IP的代碼
(假設您有一個用於 Telnet 部分的方法sendRouterCommand
— 見上文。 )
使用上述示例路由器,以下代碼獲取 WAN IP:
private bool getWanIp(ref string wanIP)
{
string routerResponse = sendRouterCommand("connection list");
return (getWanIpFromRouterResponse(routerResponse, out wanIP));
}
private bool getWanIpFromRouterResponse(string routerResponse, out string ipResult)
{
ipResult = null;
string[] responseLines = routerResponse.Split(new char[] { '\n' });
// RESP: 3947 17.110.226. 13:443 146.200.253. 16:60642 [R..A] Internet 6 tcp 128
//<------------------ 39 -------------><--- 15 --->
const int offset = 39, length = 15;
foreach (string line in responseLines)
{
if (line.Length > (offset + length) && line.Contains("Internet"))
{
ipResult = line.Substring(39, 15).Replace(" ", "");
return true;
}
}
return false;
}
大多數答案在解決方案中都提到了http://checkip.dyndns.org 。 對我們來說,效果並不好。 我們已經面對 Timemouts 很多時間了。 如果您的程序依賴於 IP 檢測,那真的很麻煩。
作為一種解決方案,我們在我們的一個桌面應用程序中使用以下方法:
// Returns external/public ip
protected string GetExternalIP()
{
try
{
using (MyWebClient client = new MyWebClient())
{
client.Headers["User-Agent"] =
"Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) " +
"(compatible; MSIE 6.0; Windows NT 5.1; " +
".NET CLR 1.1.4322; .NET CLR 2.0.50727)";
try
{
byte[] arr = client.DownloadData("http://checkip.amazonaws.com/");
string response = System.Text.Encoding.UTF8.GetString(arr);
return response.Trim();
}
catch (WebException ex)
{
// Reproduce timeout: http://checkip.amazonaws.com:81/
// trying with another site
try
{
byte[] arr = client.DownloadData("http://icanhazip.com/");
string response = System.Text.Encoding.UTF8.GetString(arr);
return response.Trim();
}
catch (WebException exc)
{ return "Undefined"; }
}
}
}
catch (Exception ex)
{
// TODO: Log trace
return "Undefined";
}
}
好的部分是,兩個站點都以純格式返回 IP。 因此避免了字符串操作。
要檢查catch
子句中的邏輯,您可以通過點擊非可用端口來重現 Timeout。 例如: http ://checkip.amazonaws.com:81/
IPIFY API很好,因為它可以以原始文本和 JSON 響應。 它還可以進行回調等。唯一的問題是它以 IPv4 響應,而不是 6。
public string GetClientIp() {
var ipAddress = string.Empty;
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null) {
ipAddress = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
} else if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_CLIENT_IP"] != null &&
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_CLIENT_IP"].Length != 0) {
ipAddress = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_CLIENT_IP"];
} else if (System.Web.HttpContext.Current.Request.UserHostAddress.Length != 0) {
ipAddress = System.Web.HttpContext.Current.Request.UserHostName;
}
return ipAddress;
}
完美運行
using System.Net;
private string GetWorldIP()
{
String url = "http://bot.whatismyipaddress.com/";
String result = null;
try
{
WebClient client = new WebClient();
result = client.DownloadString(url);
return result;
}
catch (Exception ex) { return "127.0.0.1"; }
}
使用環回作為后備,這樣事情就不會致命地破壞。
我和 Jesper 幾乎一樣,只是我重用了 webclient 並正確處理了它。 此外,我通過在末尾刪除額外的 \n 來清理一些響應。
private static IPAddress GetExternalIp () {
using (WebClient client = new WebClient()) {
List<String> hosts = new List<String>();
hosts.Add("https://icanhazip.com");
hosts.Add("https://api.ipify.org");
hosts.Add("https://ipinfo.io/ip");
hosts.Add("https://wtfismyip.com/text");
hosts.Add("https://checkip.amazonaws.com/");
hosts.Add("https://bot.whatismyipaddress.com/");
hosts.Add("https://ipecho.net/plain");
foreach (String host in hosts) {
try {
String ipAdressString = client.DownloadString(host);
ipAdressString = ipAdressString.Replace("\n", "");
return IPAddress.Parse(ipAdressString);
} catch {
}
}
}
return null;
}
WebClient、WebRequest 等很多都已過時,考慮使用它:
public static IPAddress? GetExternalIP ()
{
try
{
using (var client = new HttpClient())
return IPAddress.Parse(client.GetAsync("http://ipinfo.io/ip").Result.Content.ReadAsStringAsync().Result);
}
catch (Exception ex)
{
return null;
}
}
或者這個,它工作得很好,我認為我需要什么。 它來自這里。
public IPAddress GetExternalIP()
{
WebClient lol = new WebClient();
string str = lol.DownloadString("http://www.ip-adress.com/");
string pattern = "<h2>My IP address is: (.+)</h2>"
MatchCollection matches1 = Regex.Matches(str, pattern);
string ip = matches1(0).ToString;
ip = ip.Remove(0, 21);
ip = ip.Replace("
", "");
ip = ip.Replace(" ", "");
return IPAddress.Parse(ip);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.