前言
最近遇到一個(gè)需求(其實(shí)是閑著無聊)浓镜,需要在客戶端上實(shí)時(shí)顯示當(dāng)前的上行速度和下行速度和網(wǎng)絡(luò)類型扣墩。目前關(guān)于iOS測速的文章和demo網(wǎng)上一搜一大堆萨惑,基本上使用的方法都一致更舞,這里只是對這些方法做出總結(jié)劈猿。
我們常說的網(wǎng)速是什么拙吉?
為了解釋這個(gè)名詞,我專門搜索了我國最大的網(wǎng)絡(luò)百科全書:百度百科揪荣。果不其然筷黔,百度百科早就收錄了“網(wǎng)速”這個(gè)詞條。并且通過了“科普中國”百科科學(xué)詞條編寫與應(yīng)用工作項(xiàng)目的審核仗颈,收到了1873位網(wǎng)友的點(diǎn)贊和39次轉(zhuǎn)發(fā)佛舱。
“網(wǎng)速一般是指電腦或手機(jī)上網(wǎng)時(shí)椎例,上傳和下載數(shù)據(jù)時(shí),請求和返回?cái)?shù)據(jù)所用的時(shí)間長短请祖《┩幔”這句話可以分開兩部分理解。上傳數(shù)據(jù)時(shí)肆捕,請求所用的時(shí)間長短刷晋,和下載數(shù)據(jù)時(shí),返回?cái)?shù)據(jù)所用的時(shí)間長短慎陵。這其中眼虱,數(shù)據(jù)量和時(shí)間的比值,就是網(wǎng)速席纽。
比如下載或上傳一個(gè)10KB的文件捏悬,需要1秒,則網(wǎng)速為10KB/S
題外話:作為蘋果用戶润梯,非常羨慕安卓系統(tǒng)能在狀態(tài)欄上顯示實(shí)時(shí)的上下載速度过牙。而iOS系統(tǒng),只能用一種曲線救國的方式:weight纺铭。什么寇钉?你不知道weight?拿起你的手機(jī)彤蔽,使勁向左滑摧莽,這個(gè)界面上的小框框就是weight庙洼。
圖中的SYS Pro這個(gè)應(yīng)用顿痪,就能在weight中實(shí)時(shí)顯示網(wǎng)速。
如何測速
方法一
有了公式油够,我們就能很很輕松的計(jì)算出當(dāng)前網(wǎng)速蚁袭。
公式中有兩個(gè)變量,“數(shù)據(jù)量”和“時(shí)間”石咬。固定某一變量揩悄,統(tǒng)計(jì)另一變量的變化量。如固定時(shí)間鬼悠,統(tǒng)計(jì)在單位時(shí)間內(nèi)(假設(shè)為1秒)删性,最大的下載數(shù)據(jù)量,就能得到當(dāng)前下行速度焕窝。而固定數(shù)據(jù)量蹬挺,統(tǒng)計(jì)下載時(shí)間,也能算出下行速度它掂,但是需要注意的是巴帮,這時(shí)候算出的值為平均速度,并不是單位時(shí)間內(nèi)的下載速度。
這種方式的優(yōu)點(diǎn)自然是算出來的值比較準(zhǔn)確榕茧。而缺點(diǎn)是需要消耗一定的流量垃沦,在當(dāng)時(shí)5元30M的年代(現(xiàn)在依舊是5元30M),用戶估計(jì)要怒刪應(yīng)用了用押。
還有一個(gè)缺點(diǎn)是一個(gè)TCP連接可能無法充分利用當(dāng)前網(wǎng)絡(luò)肢簿,需要多個(gè)鏈接一起榨干網(wǎng)絡(luò)。
方法二
這個(gè)需求需要實(shí)時(shí)的顯示網(wǎng)速蜻拨,所以方法一不太行得通译仗。那如何獲取當(dāng)前實(shí)時(shí)的網(wǎng)速呢?那就要祭出Uinx結(jié)構(gòu)體:ifaddrs
這個(gè)結(jié)構(gòu)體在頭文件ifaddrs.h
中定義官觅,能獲取所有網(wǎng)卡的數(shù)據(jù)纵菌。
詳細(xì)如下
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface 端口名稱*/
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS 接口標(biāo)志*/
struct sockaddr *ifa_addr; /* Address of interface 本機(jī)IP*/
struct sockaddr *ifa_netmask; /* Netmask of interface 子網(wǎng)掩碼*/
struct sockaddr *ifa_dstaddr; /* Point-to-point destination address 對端地址*/
void *ifa_data; /* Address-specific data 接口信息數(shù)據(jù)*/
};
這個(gè)結(jié)構(gòu)體的詳細(xì)描述可以查看這個(gè)網(wǎng)頁:ifaddrs
其中的ifa_data中的ifi_ibytes
和ifi_obytes
就是我們需要的數(shù)據(jù)。
/*
* Structure describing information about an interface
* which may be of interest to management entities.
*/
struct if_data {
/* generic interface information */
u_char ifi_type; /* ethernet, tokenring, etc */
u_char ifi_typelen; /* Length of frame type id */
u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */
u_char ifi_addrlen; /* media address length */
u_char ifi_hdrlen; /* media header length */
u_char ifi_recvquota; /* polling quota for receive intrs */
u_char ifi_xmitquota; /* polling quota for xmit intrs */
u_char ifi_unused1; /* for future use */
u_int32_t ifi_mtu; /* maximum transmission unit */
u_int32_t ifi_metric; /* routing metric (external only) */
u_int32_t ifi_baudrate; /* linespeed */
/* volatile statistics */
u_int32_t ifi_ipackets; /* packets received on interface */
u_int32_t ifi_ierrors; /* input errors on interface */
u_int32_t ifi_opackets; /* packets sent on interface */
u_int32_t ifi_oerrors; /* output errors on interface */
u_int32_t ifi_collisions; /* collisions on csma interfaces */
u_int32_t ifi_ibytes; /* total number of octets received */
u_int32_t ifi_obytes; /* total number of octets sent */
u_int32_t ifi_imcasts; /* packets received via multicast */
u_int32_t ifi_omcasts; /* packets sent via multicast */
u_int32_t ifi_iqdrops; /* dropped on input, this interface */
u_int32_t ifi_noproto; /* destined for unsupported protocol */
u_int32_t ifi_recvtiming; /* usec spent receiving when timing */
u_int32_t ifi_xmittiming; /* usec spent xmitting when timing */
struct IF_DATA_TIMEVAL ifi_lastchange; /* time of last administrative change */
u_int32_t ifi_unused2; /* used to be the default_proto */
u_int32_t ifi_hwassist; /* HW offload capabilities */
u_int32_t ifi_reserved1; /* for future use */
u_int32_t ifi_reserved2; /* for future use */
};
只要讀取上一秒網(wǎng)卡中的流量使用情況休涤,再讀取當(dāng)前的流量使用情況咱圆,就可以計(jì)算出網(wǎng)速。
針對第二種情況功氨,用OC寫了一個(gè)簡單的Demo序苏,放在:https://github.com/OYQ/OYTool/tree/master/OYNetSpeedTool-Objc
- 需要注意的是,demo中并不是每一秒計(jì)算一次網(wǎng)速捷凄,而是每兩秒計(jì)算一次忱详,因?yàn)槿粘J褂弥胁⒉恍枰珳?zhǔn)的計(jì)算,并且大量的計(jì)算會(huì)消耗性能跺涤。
參考資料
iOS如何進(jìn)行網(wǎng)絡(luò)測速-Joy__
iOS 網(wǎng)速測試-godBlessMe__
IOS網(wǎng)速測試-角燈的技術(shù)博客