HTTPDNSLib - 一個支持 DNSPod D+ 和自定義 HttpDNS 服務的 HttpDNS SDK(Android)
該項目是手機微博研發團隊和手機微博技術保障部共同努力的成果。
在此特別感謝:
張杰 微博:@木澤水
王春生 微博:@平凡的香草
胡波 微博:@胡波_
韓超 微博:@超朝炒觘
趙星宇 微博:@淘淘不逃008
聶鈺 微博:@古夜
馮磊 微博:@馮磊424
等同學的支持。 感謝大家提出的寶貴意見,感謝大家為該項目付出的努力!
項目中有任何問題歡迎大家來吐槽,一起完善、一起提高、一起使用!
接入說明:
由于該工程需要用戶自定義部分配置文件,所以建議以源碼方式使用。(同時也支持項目中設定lib庫的參數) lib庫目前還沒有打包成 jar 文件, 大家測試使用的話可以直接將工程包含到自己的工程內即可。 apk文件夾下內有打包好的對httpDNS庫進行測試的程序。 該測試程序模擬了用戶使用的場景,并且記錄了相關統計數據。以及Lib庫的時時的狀態信息。
在AndroidManifest.xml文件中需要配置
<!-- 主要注冊一個廣播 監聽網絡發生變化,本地更新dns解析記錄--> <receiver android:name="com.sina.util.networktype.NetworkStateReceiver" android:label="NetworkConnection" > <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.intent.action.USER_PRESENT" /> </intent-filter> </receiver> <!-- 需要配置的權限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在使用 http dns前 需要初始化一次
DNSCache.Init(this);
直接調用該方法獲取 A記錄對象
DomainInfo[] infoList = DNSCache.getInstance().getDomainServerIp( " http://api.weibo.cn/index.html " ) ;
//DomainInfo 返回有可能為null,如果為空則使用域名直接請求數據吧~ 因為在http server 故障的時候會出現這個問題。
if( infoList != null ) { //A記錄可能會返回多個, 沒有特殊需求直接使用第一個即可。 這個數組是經過排序的。 DomainInfo domainModel = infoList[0] ; //這里是 android 請求網絡。 只需要在http頭里添加一個數據即可。 省下的請求數據和原先一樣。 HttpGet getMethod = new HttpGet( domainModel.url ); getMethod.setHeader("host", domainModel.host); HttpClient httpClient = new DefaultHttpClient(); long startDomainRequests = System.currentTimeMillis(); HttpResponse response = httpClient.execute(getMethod); String res = EntityUtils.toString(response.getEntity(), "utf-8") ; Log.d("DINFO", res) ; //在請求倒數據后,請配合將一部分信息傳遞給我。 lib庫里面會對這個服務器進行評分計算,lib庫永遠會優先給你最快,最穩定的服務器地址。 domainModel.code = String.valueOf( response.getStatusLine().getStatusCode() ); domainModel.data = res ; domainModel.startTime = String.valueOf(startDomainRequests) ; DNSCache.getInstance().setDomainServerIpInfo( domainModel ); }
更多配置
你可以創建一個 com.sina.util.dnscache.DNSCacheConfig.Data 對象分別設置下面屬性。然后調用 DNSCacheConfig.saveLocalConfigAndSync 方法傳入 設定好的 配置選項。
/** * 是否啟用自己家的HTTP_DNS服務器 默認不啟用 | 1啟用 0不啟用 */ public String IS_MY_HTTP_SERVER = null; /** * 自己家HTTP_DNS服務API地址 使用時直接在字符串后面拼接domain地址 | * 示例(http://xxx.xxx.xxx.xxx/dns?domain=)+ domain */ public String HTTPDNS_SERVER_API = null; /** * 是否啟用dnspod服務器 默認不啟用 | 1啟用 0不啟用 */ public String IS_DNSPOD_SERVER = null; /** * DNSPOD HTTP_DNS 服務器API地址 | 默認(http://119.29.29.29/d?ttl=1&dn=) */ public String DNSPOD_SERVER_API = null; /** * DNSPOD 企業級ID配置選項 */ public String DNSPOD_ID = null; /** * DNSPOD 企業級KEY配置選項 */ public String DNSPOD_KEY = null; /** * 是否開啟 本地排序插件算法 默認開啟 | 1開啟 0不開啟 */ public String IS_SORT = null; /** * 速度插件 比重分配值:默認40% */ public String SPEEDTEST_PLUGIN_NUM = null; /** * 服務器推薦優先級插件 比重分配:默認30% (需要自家HTTP_DNS服務器支持) */ public String PRIORITY_PLUGIN_NUM = null; /** * 歷史成功次數計算插件 比重分配:默認10% */ public String SUCCESSNUM_PLUGIN_NUM = null; /** * 歷史錯誤次數計算插件 比重分配:默認10% */ public String ERRNUM_PLUGIN_NUM = null; /** * 最后一次成功時間計算插件 比重分配:默認10% */ public String SUCCESSTIME_PLUGIN_NUM = null; /** * domain對應的測速文件,如果需要對服務器進行測速請給domain設置一個可以下載的資源文件來計算服務器速度 */ public ArrayList<String> SPEEDPATH_LIST = new ArrayList<String>();
動態更新參數
DNSCacheConfig 類下的 ConfigText_API 字段可以配置成自動更新配置參數的接口。 該接口返回json數據類型 具體數據格式詳見DNSCacheConfig.Data toJson()方法。
自己家HttpDNS服務接入
首先開啟 DNSCacheConfig.Data.IS_MY_HTTP_SERVER = 1 ; 然后設定 DNSCacheConfig.Data.HTTPDNS_SERVER_API 接口地址 示例( http://XXX.XXX.XXX.XXX/dns?domain=)+ domain
該接口返回格式(當然你也可以自定義格式需要重載 com.sina.util.dnscache.httpdns.IJsonParser 類即可): { "domain": "api.weibo.cn", "device_ip": "10.209.70.192", "device_sp": "0", "dns": [ { "priority": "0", "ip": "123.125.105.231", "ttl": "60" }, { "priority": "0", "ip": "123.125.105.246", "ttl": "60" }, { "priority": "0", "ip": "202.108.7.133", "ttl": "60" } ] } PS: priority 字段是服務器推薦優先級。 | device_sp 字段是該設備出口運營商。
HttpDns是什么?
如果你對 httpdns 還不了解他是什么!
傳統DNS解析 和 HTTPDNS解析 本質的區別:
傳統DNS解析
客戶端發送udp數據包到dns服務器,dns服務器返回該域名的相關A記錄信息。
HTTPDNS解析
客戶端發起http請求攜帶需要查詢的域名,通過IP直接訪問服務器,該Http服務器接倒請求后返回域名對應的A記錄。
HttpDns sdk (android版本)
希望解決的問題:
1.LocalDNS劫持 2.平均訪問延遲下降 3.用戶連接失敗率下降
目錄結構說明:
HttpDns/code/DNSCache --- HttpDns lib庫主工程。 HttpDns/code/DNSCacheTest --- HttpDns庫測試工程。 HttpDns/doc --- 項目相關的一些文檔、流程圖、結構圖等。 HttpDns/ui/DNSCacheTest --- 存放HttpDns測試項目UI源文件以及切圖文件。
HttpDns 交互流程
HttpDns Lib庫交互流程
查詢模塊
檢測本地是否有相應的域名緩存 沒有記錄則根據當前運營商返回內置的ip節點 從httpdns查詢域名相應A記錄,緩存域名信息 查詢模塊必須保證響應速度,基于已有設備測試平均在5毫秒左右
數據緩存模塊
根據sp(或wifi名)緩存域名信息 根據sp(或wifi名)緩存服務器ip信息、優先級 記錄服務器ip每次請求成功數、錯誤數 記錄服務器ip最后成功訪問時間、最后測速 添加 內存 -》數據庫 之間的緩存層
評估模塊
根據本地數據,對一組ip排序 處理用戶反饋回來的請求明細,入庫 針對用戶反饋是失敗請求,進行分析上報預警 給HttpDns服務端智能分配A記錄提供數據依據
評估算法插件
本次測速 - 對ip組的每個ip測速打分 官方推薦 - HttpDns接口 A記錄中返回的優先級 歷史成功 - 該ip7天內成功訪問次數 歷史錯誤 - 該ip7天內訪問錯誤次數 最后成功時間 - 該ip最后一次成功時間,閾值24
打分比重權值分配
對每個IP打分,總分100分。 本次測速 - 40分 官方推薦 - 30分 歷史成功 - 10分 歷史錯誤 - 10分 最后成功時間 - 10分 總分=本次測速+官方推薦+歷史成功次數+歷史錯誤次數+最后成功時間
目前權重分配完全基于主觀認識,后期會根據建立的相應基線進行權重分配調整。
使用者需要自己權衡,有可能隨機的ip速度都好于權重打分的ip。
PS:給出一副算法計算分數時的細節圖,有興趣的朋友可以一起探討研究。

你可能更需要“它” HttpHook(android版本)(工程還未上傳)
HttpHook是一個轉發http請求工具庫。
他可以讓你在不修改工程源代碼的情況下對網絡層進行修改、替換、等更多的操作。
由于我沒有微博客戶端的源碼,為了測試微博客戶端是否可以正常使用httpdns庫,才誕生的這個項目。
HttpHook 截取 api.weibo.cn 的所有請求,提取到url。
將url中的host域名,傳入httpdns庫中,使用返回的a記錄替換host,進行訪問。
訪問服務器成功后,在將服務器返回的數據傳給 客戶端,從而完成一次訪問請求。
這是在 httpdns 項目中使用場景。 大家如果感興趣可以到httphook項目中詳細查看。
HttpDns Test (android版本)
測試工程主要最初為了模擬用戶使用APP發出的網絡請求,進行數據記錄和對比。
在頁面中能很直觀的看到每個任務的相關信息。
比如:任務總耗時,httpdns lib庫耗時、http請求耗時、以及設備當前環境信息 等。。
由于UE,UI都是自己設計,對于表達信息的布局和美觀可能還有欠缺,本程序猿的能力有限,大家多多包涵。