CODE-在Windows 7/2008取得Web Server IP
4 |
過去做專案時,偶爾會有需要記錄ASP.NET所在主機IP的需求,最常見的情境是Web Farm有多台主機,在寫入資料庫時希望一併保留該主機的IP,方便追查問題時找到正確的機器調閱IIS Log。
我常用的寫法是先用Dns.GetHostName()取得主機名稱,再用Dns.GetHostEntry().AddressList將主機名稱對應成IP網址,雖然多網卡時會傳回多筆,但原則上我們取第一筆就足以產生識別效果:
System.Net.Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
最近發現上述的寫法在Windows 2008/Windows 7上會有問題!
Vista以後的Windows作業系統,IPv6已成預設選項,網卡預設會啟用IPv6協定,所以Dns.GetHostEntry().AddressList傳回的第一筆將會是類似fe80::876:605b:8f95:dd2a%13格式的Link-local IPv6網址。即便停用IPv6協定,第一筆傳回的仍不是IPv4網址,而是::1的本機IPv6網址(相當於127.0.0.1)。
為了克服這個問題,我在程式加上First(o => o.AddressFamily == AddressFamily.InterNetwork),變成查IPv4的第一筆IP位址就可避開IPv6問題:
Dns.GetHostEntry(Dns.GetHostName()).AddressList.First(o => o.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
這裡用了LINQ的First來簡化程式碼,若是ASP.NET 3.5以前的版本,則可用迴圈替代:
string ipStr = "";
foreach (IPAddress ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
ipStr = ip.ToString();
break;
}
以下是測試網頁:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.Linq" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
foreach (IPAddress ip in
Dns.GetHostEntry(Dns.GetHostName()).AddressList)
Response.Write("<li>" + ip.ToString());
string ip1 =
Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
string ip2 =
Dns.GetHostEntry(Dns.GetHostName()).AddressList
.First(o => o.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
.ToString();
Response.Write(string.Format("<hr />IP1:{0}<br />IP2:{1}", ip1, ip2));
Response.End();
}
</script>
2011/01/01補充: 有網友詢問為何不用Request.ServerVariables["LOCAL_ADDR"]? 原因是該變數是以Request觀點取得的網路IP位址,而Web Farm主機的每一台主機對外呈現的都是同一個IP,再靠Layer 4 Switch或負載平衡機制分配到不同主機上,故Web Farm每一台主機用Request.ServerVariables["LOCAL_ADDR"]將會是相同的,用文中的方法才有辦法取得真實的IP位址。
Comments
# by 91
喔喔!我要把這篇文章收起來! 感謝黑大的分享~
# by shihwei
感謝黑大,之前在抓ServerIP也有部分電腦出現「::1」的狀況, 後來是使用Dns.Resolve(Dns.GetHostName()).AddressList(0).ToString()找出ServerIP, 只是一直沒有什頭緒為什麼會出「::1」,後來看了「C:\Windows\System32\drivers\etc\hosts」中有行「# ::1 localhost」時,有種說不出的感覺…
# by 汽車借款
很有用處耶,感謝版主的分享!
# by shihwei
哦… 我剛才查到Dns.Resolve 這個 API 現在已經過時… XD 還是用黑大的方法比較明確!!!