背景:博主本是一位Windows桌面應用程序開發工程師,對網絡通信一知半解。一日老婆逛完某寶,問:“為什麼他們知道我的地址呢,他們是怎麼獲取我的地址的呢?”
順著這個問題我們的探秘開始:
第一步:簡單的服務搭建
思路,通過HttpListener在本地搭建一個簡易的服務器,開發程序為控制台接口,核心類 HttpListenerService:
方法 Start()開啟線程池針對指定IP進行監聽,本地的端口選取的9527(周星馳唐伯虎點秋香在華府的編號)
public void Start(object obj) { try { //指定身份驗證 Anonymous匿名訪問 _httpListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous; //GetLocalIpAddress()----獲取本地IP的方法 _httpListener.Prefixes.Add("http://" + GetLocalIpAddress() + ":9527/"); _httpListener.Start(); //等待請求連接 while (true) { //等待請求連接 //沒有請求則GetContext處於阻塞狀態 var ctx = _httpListener.GetContext(); ThreadPool.QueueUserWorkItem(TaskProc, ctx); } } catch (Exception ex) { throw; } }
第二步:獲取客戶端request的IP地址
網上查詢了很多例子,感覺太復雜了,自己通過VS的快速監視功能發現有一個屬性 RemoteEndPoint 可以獲取客戶端IP和端口號 ,其實應該根據Get和POST進行區分,為了方便暫時省略
1 private void TaskProc(object o) 2 { 3 try 4 {; 5 var ctx = (HttpListenerContext) o; 6 string ipAddress = null; 7 if (ctx.Request.RemoteEndPoint != null) 8 { 9 ipAddress = ctx.Request.RemoteEndPoint.Address.ToString(); 10 } 11 //後面的暫時不用看,已經獲取到客戶端訪問IP 12 var encoding = Encoding.GetEncoding("gb2312"); 13 var callbackData = JsonConvert.SerializeObject(IpGetCity(GetOuterNetIp())); 14 var data = encoding.GetBytes(callbackData); 15 ctx.Response.StatusCode = 200; 16 ctx.Response.Close(data, false); 17 } 18 catch (Exception ex) 19 { 20 } 21 }
第三步:如何根據客戶端的IP獲取,客戶端所在的地址,因為事情起源來自淘寶,所以就 查詢淘寶是否有類似的接口,果然經過搜索後查到 http://ip.taobao.com/service/getIpInfo.php?ip= 客戶IP的Json對象,通過Fiddler解析返回數據,創建對應Json格式對象,封裝獲取方法
1 public static Result IpGetCity(string ipAddres) 2 { 3 try 4 { 5 if (!ValidateIpAddress(ipAddres)) return null; 6 7 var url = new Uri("http://ip.taobao.com/service/getIpInfo.php?ip=" + ipAddres); 8 var request = (HttpWebRequest) WebRequest.Create(url); 9 request.Timeout = 1000*5; 10 request.KeepAlive = false; 11 request.Method = "GET"; 12 var resoponse = request.GetResponse(); 13 string pageHtml; 14 // ReSharper disable once AssignNullToNotNullAttribute 15 using (var stream = new StreamReader(resoponse.GetResponseStream())) 16 { 17 pageHtml = stream.ReadToEnd(); 18 } 19 var data = JsonConvert.DeserializeObject<Result>(pageHtml); 20 return data; 21 } 22 catch (WebException webEx) 23 { 24 throw; 25 } 26 }
第四步:測試。 因為本地是局域網,發送IP地址後返回肯定為空,先嘗試查詢本地外網IP,那麼如何獲取本地的外網IP呢?還是同前面的思路一樣,網絡查詢類似的接口,百度一下直接根據第一個搜索的結果查詢,http://1212.ip138.com,建立webrequest請求,抓取Html數據
1 public static string GetOuterNetIp() 2 { 3 var tempIp = ""; 4 try 5 { 6 WebRequest wr = (HttpWebRequest) WebRequest.Create("http://1212.ip138.com"); 7 var stream = wr.GetResponse().GetResponseStream(); 8 var sr = new StreamReader(stream, Encoding.GetEncoding("gb2312")); 9 var all = sr.ReadToEnd(); 10 //讀取網站的數據 11 var start = all.IndexOf("您的IP是:[", StringComparison.Ordinal) + 7; 12 var end = all.IndexOf("]", start, StringComparison.Ordinal); 13 tempIp = all.Substring(start, end - start); 14 sr.Close(); 15 stream.Close(); 16 } 17 catch 18 { 19 // ignored 20 } 21 return tempIp; 22 }
但是問題出現了,為什麼我浏覽器獲取的數據可以得到本機的IP,但是我建立的連接獲取的請求卻是這樣
經過分析後發現,這個網址試用iframe框架進行處理,無法獲取到frame框架的內部信息,然後抓去frame信息發現其實他真正請求的路徑為 http://1212.ip138.com/ic.asp,該網站的編碼格式為gb2312,再次發送請求獲取返回數據:
雖然大概了解的一些,但是比如用戶用代理服務器訪問等一系列的問題還是需要我繼續去探索!