linuxifa
❶ 從ip addr add和ifconfig的區別看linux網卡ip地址的結構
如果你非常理解網路協議的原理以及網路的分層架構那麼我想你就不會有這個問題,實際上,每一個網卡設備都有一個mac地址,但是卻可 以有多個網路層地址,比如IP地址,然而這個事實無法很好地像用戶提供操作介面,所以就引出了ip別名(IP aliases)和輔助ip(secondary IP addresses)的概念。其實很容易理解這個事實,按照分層的思想,下層總是為上層服務,也就是為上層提供舞台,上層利用下層的服務,而不必讓下層知 道自己的情況,如果一個擁有合理mac地址的網卡沒有配置網路層地址(比如IP地址)這件事合理的話,那麼為這個設備配置多個IP地址也是合理的,正好像 一個ip可以對應多個應用層埠一樣,也就是說,下層對上層總是一對多的關系,在分層架構中這種關系是合理的。下面我們就看一下linux的網卡的ip地 址結構。剛才說了在linux中,一個網卡可以有多個IP,那麼這多個ip有什麼關系呢?其實這些ip組成了一個吊鏈結構,所謂吊鏈結構就是一些節點鏈接 成一條鏈,然後每個節點帶有自己的一條鏈
每個節點代表的ip地址標識一個網段,這個節點的ip就是這個網段的 Primary地址,它下面所帶的ip就是這個網段的Secondary地址,也就是說一個網卡可以帶有各個節點所帶鏈表長度之和個ip地址,而且這些 ip不是線形的,而是上述的吊鏈結構。我們看一下這么做有什麼好處。玩過Cisco路由器的朋友可能都知道有個Secondary IP的概念,這個特性可以創建邏輯子網,也就是說在一個物理網口上連接兩個子網,這咋看起來好像不可思議,其實很簡單,比如這個網口接到一台交換機上,如 果這個網口沒有配置Secondary IP的話,那麼這台交換機只能連接一個網段的主機,比如192.168.1.1/24,但是,如果它配置了Secondary IP,那麼就可以連接兩個網段的主機,比如192.168.1.1/24和10.0.0.1/24,道理就是這么簡單,但是卻很有用,該機制可以被路由匯 總策略所使用。注意上面這個例子中的Secondary IP不是這里說的linux的Secondary address,在linux中恰恰相反,只要一個網卡上配置的ip不是一個網段的,那麼都是Primary IP,就是吊鏈結構中上面的那條主鏈中的IP,linux中的Secondary address是主鏈結點的子鏈結點中的IP,這一點一定注意,概念是不能混淆的。前面說的只是吊鏈中主鏈的作用,那麼子鏈呢?其實想像一下也很簡單,比 如一台機器上運行著一個代理伺服器或者負載均衡服務,代理伺服器或者負載均衡服務和主伺服器要監聽相同的埠,那麼就可以用secondary address來解決了,只要需要在同一網段監聽同一個埠的應用都是吊鏈中子鏈存在的原因,因此可以說,主鏈對外部或者說對下面鏈路層虛擬了多塊網卡, 而子鏈向上層虛擬了多台機器,配置了吊鏈結構的linux主機如果說只有一塊網卡,那麼外部會認為它有多塊網卡,對於內部,應用層會認為彼此在不同的主機 上,這就是效果。 除了上面大體的介紹之外,還有很多細節,吊鏈在主鏈上是沒有主次的,子鏈除了第一個節點其它節點也不分主次,都是平行的關系,但是子鏈中的第一個節點總是 鏈接在主鏈中,它們攜帶的地址就是primary地址,它們下面隸屬的子鏈攜帶的地址就是這個primary地址的secondary地址,如此看來,一 旦主鏈上一個節點被刪除了,那麼它的子鏈也將不復存在,所謂皮之不存毛將焉附。但是這種策略總是顯得不是那麼優美,因為父親犯錯,兒子也要受連累,這在現 代社會早就不時行了,那麼就需要改變機制了,因此linux中特意有了一個選項,就是當一個primary地址被刪除時,如果它有secondary地址 的話,那麼它的第一個secondary地址(長子)繼承被刪除的primary地址的位置成為primary地址,這樣就顯得很合理了,要不然在刪除 primary地址的時候,如果有程序用secondary地址,那麼要麼延遲刪除,要麼程序崩潰,採用自動提升策略的話就不會出現問題。 至於說IP aliases,那是以前版本有的了,就是一個實現問題,解決的問題和現在的secondary IP機制一樣,它主要就是在物理網卡名字後面加上後綴從而成為虛擬網路介面,本質上和secondary IP機制沒有區別,區別就是IP aliases顯得不是那麼直觀,而secondary IP卻是真正讓應用看到了一個網卡的多個地址,比如你要是用IP aliases的話,有的時候你總是會問eth0:0是什麼?我就曾經在內核裡面拚命找eth0:0這個網路設備的注冊代碼,都要瘋掉了也沒有找到,其實 我並不是很傻,但是我卻因為那個該死的名字作出了傻事。 下面就可以看看linux內核的實現代碼了,首先弄明白一些數據結構,最重要的就是net_device,其次就是in_device,然後就是in_ifaddr,明白了這三個數據結構,一切就明白了,這是真的。
struct net_device { ... void *ip_ptr; //指向一個in_device結構,這欄位從net_device中分離表明一個網卡可以支持多種網路層協議的 ... } struct in_device { struct net_device *dev; //指向它隸屬的net_device,也就是網卡 atomic_t refcnt; //引用計數 int dead; struct in_ifaddr *ifa_list; //所有的ip地址鏈表 ... }; struct in_ifaddr //代表一個ip地址 { struct in_ifaddr *ifa_next; //上面的in_device中的ifa_list欄位就是靠這個欄位連成鏈的 struct in_device *ifa_dev; //回指in_device結構 struct rcu_head rcu_head; u32 ifa_local; //ip地址 u32 ifa_address; u32 ifa_mask; //掩碼 u32 ifa_broadcast; //廣播地址 u32 ifa_anycast; unsigned char ifa_scope; unsigned char ifa_flags; //只有IFA_F_SECONDARY標志,因為除了這個就是primary地址了 unsigned char ifa_prefixlen; char ifa_label[IFNAMSIZ]; //名字,在ip aliases時代,它就可能是ethx:y的形式,在secondary ip時代,它統一就是ethx };注 意,上面的結構並沒有將linux網卡的ip地址結構表示為吊鏈結構,所謂的吊鏈結構只是邏輯上的,在數據結構上,一個網卡所有的ip地址全部都在 ifa_list中被鏈接成一個線性的鏈表,至於是primary地址還是secondary地址就看in_ifaddr的ifa_flags欄位了。每 當有新的地址被設置的時候,inet_insert_ifa總是被調用,linux為何沒有在代碼上將ip地址表示為吊鏈結構呢?我也不知道,個人感覺一 個net_device帶有一個primary ip鏈表,然後每個primary ip節點帶有一個secondary ip鏈表,這樣會更好一些的,我覺得inet_insert_ifa實現的十分拙劣。添加地址可以通過兩個用戶空間程序搞定,一個是ifconfig,另 一個是ip addr add,ifconfig是基於ioctl進行地址添加的,而ip程序是基於netlink進行地址添加的,不管哪一種方式都可以達到目的,現在就可以看 看另一個問題了:為何用ip addr add添加的ip地址用ifconfig看不到,而ifconfig設置的地址ip addr show卻是可以看到。這個問題通過看代碼一眼就可以明白,在ifconfig獲得ip地址的時候,代碼:
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { if (!strcmp(ifr.ifr_name, ifa->ifa_label) && sin_orig.sin_addr.s_addr == ifa->ifa_address) { break; } }取 的是這個被找到的ifa的ip地址,而我們知道,所有的ifa鏈接成一個線性鏈表,那麼找到了第一個就不會再往後走了,因此只能得到一個結果,就是鏈表最 前面的那個,而ip add show就不同了,具體在函數inet_mp_ifaddr中實現,該函數遍歷所有的ifa,並且傳到用戶空間緩沖區。這里可以做一個實驗:首先用 ip addr add添加幾個不在同一個網段的primary ip地址,然後再ifconfig一個和前面的ip都不在一個網段的ip,然後可以用ifconfig查看一下,發現不是剛剛用ifconfig設置進去 的那個ip,而是用ip addr add添加進去的,這就說明ifconfig永遠都是取的ifa鏈表最前面的那一個,還有一點要注意,就是如果你用ip addr add添加了很多的secondary ip地址,那麼恰好你用ifconfig設置的ip地址和那些secondary ip在一個網段,那麼所有的secondary ip都將被刪除,這些都是sencondary ip的規范決定的,而且在代碼中也有體現。另外還要注意,路由表的表項都是基於primary ip的,因為所有的操作都是以primary ip為主的,比如在添加路由的時候:
void fib_add_ifaddr(struct in_ifaddr *ifa) { struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; ... if (ifa->ifa_flags&IFA_F_SECONDARY) { //如果ifa是個sencondary地址,那麼就找到它隸屬的primary地址後然後以這個primary為主進行設置 prim = inet_ifa_byprefix(in_dev, prefix, mask); if (prim == NULL) { printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL/n"); return; } } fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); //添加進路由表 ... }到 此為止我們知道了不少東西,最重要的就是linux中網卡ip地址的吊鏈結構以及這么設計的好處,另外就是設置ip地址的方式有ioctl和 netlink。其實網卡擁有多個ip並不會帶來什麼沖突,本質上ip和網卡沒有什麼關系,它們唯一的關系就是靠網路分層模型聯系在一起的,細節上就是靠 路由聯系在一起的,比如我添加路由的時候指定了一個目的地址和下一跳ip地址以及一個網卡出口,那麼內核會根據提供的目的地址將路由插在合式的位置,然後 將nh的網路設備設置為你提供的網卡出口,等到傳輸數據的時候就會查找路由從而找到出口,就是這么簡單,你自己手動設置的路由可以隨意設置,即使完全錯誤 內核也會將之加入路由表的,還有一種路由是內核自動生成的,就是在網卡剛剛up的時候,這時通過網卡的net_device找到其in_device然後 找到其ip地址,這樣的路由稱為鏈路路由。 通過secondary IP機制,你可以認為你的機器有很多網卡,對於應用,監聽同一埠的應用會認為它們在區域網中不同的機器上,你可以隨意使用這些ip地址而不會發生混亂,路由和底層的arp會處理好這一切,當然前提是你將路由設置對。 附: 用戶空間有ifup/ifdown,/sbin/ip,ifconfig,還有netplugd守護進程,這些有何關系嗎?這中間ip程序是最基本的,沒 有任何策略,策略就是參數指定,要麼就是別的程序調用它,而netplugd就是一個監控守護進程,通過netlink監控網卡狀態,然後根據不同的監控 結果調用/etc/netplug.d/netplug腳本,進而可能調用ifup/ifdown腳本,而後者就是腳本,其中會調用ifup-eth腳 本,最終整理好參數後調用ip程序(典型的就是:ip link set eth0 up/down),當然ip程序完全可以自己調用,比如ip addr add以及ip route add等等,而ifconfig沒有那麼繞圈子,就是通過ioctl進行設置,可以通過strace來觀察。這其中奧妙大了去了,說白了就是策略和機制分 離,另外還體現出linux中的很多功能都是很小的程序組合而成的。
Linux的ip地址的吊鏈結構以及ip地址的定址特性(詳見《關於IP網段間互訪的問題—路由是根本》)充分說明了linux的協議棧實現多麼的完美,完全符合分層和封裝模型,使得下層的邏輯和上層的邏輯完全解除耦合,也就是說ip層完全不依賴鏈路層以及物理層的物理布局,最後記住,ip層事情比如定址路由只由ip層實現,之所有有鏈路層發現的路由,完全是為了方便。
❷ 從ip addr add和ifconfig的區別看linux網卡ip地址的結構
如果你非常理解網路協議的原理以及網路的分層架構那麼我想你就不會有這個問題,實際上,每一個網卡設備都有一個mac地址,但是卻可 以有多個網路層地址,比如IP地址,然而這個事實無法很好地像用戶提供操作介面,所以就引出了ip別名(IP aliases)和輔助ip(secondary IP addresses)的概念。其實很容易理解這個事實,按照分層的思想,下層總是為上層服務,也就是為上層提供舞台,上層利用下層的服務,而不必讓下層知 道自己的情況,如果一個擁有合理mac地址的網卡沒有配置網路層地址(比如IP地址)這件事合理的話,那麼為這個設備配置多個IP地址也是合理的,正好像 一個ip可以對應多個應用層埠一樣,也就是說,下層對上層總是一對多的關系,在分層架構中這種關系是合理的。下面我們就看一下linux的網卡的ip地 址結構。剛才說了在linux中,一個網卡可以有多個IP,那麼這多個ip有什麼關系呢?其實這些ip組成了一個吊鏈結構,所謂吊鏈結構就是一些節點鏈接 成一條鏈,然後每個節點帶有自己的一條鏈
每個節點代表的ip地址標識一個網段,這個節點的ip就是這個網段的 Primary地址,它下面所帶的ip就是這個網段的Secondary地址,也就是說一個網卡可以帶有各個節點所帶鏈表長度之和個ip地址,而且這些 ip不是線形的,而是上述的吊鏈結構。我們看一下這么做有什麼好處。玩過Cisco路由器的朋友可能都知道有個Secondary IP的概念,這個特性可以創建邏輯子網,也就是說在一個物理網口上連接兩個子網,這咋看起來好像不可思議,其實很簡單,比如這個網口接到一台交換機上,如 果這個網口沒有配置Secondary IP的話,那麼這台交換機只能連接一個網段的主機,比如192.168.1.1/24,但是,如果它配置了Secondary IP,那麼就可以連接兩個網段的主機,比如192.168.1.1/24和10.0.0.1/24,道理就是這么簡單,但是卻很有用,該機制可以被路由匯 總策略所使用。注意上面這個例子中的Secondary IP不是這里說的linux的Secondary address,在linux中恰恰相反,只要一個網卡上配置的ip不是一個網段的,那麼都是Primary IP,就是吊鏈結構中上面的那條主鏈中的IP,linux中的Secondary address是主鏈結點的子鏈結點中的IP,這一點一定注意,概念是不能混淆的。前面說的只是吊鏈中主鏈的作用,那麼子鏈呢?其實想像一下也很簡單,比 如一台機器上運行著一個代理伺服器或者負載均衡服務,代理伺服器或者負載均衡服務和主伺服器要監聽相同的埠,那麼就可以用secondary address來解決了,只要需要在同一網段監聽同一個埠的應用都是吊鏈中子鏈存在的原因,因此可以說,主鏈對外部或者說對下面鏈路層虛擬了多塊網卡, 而子鏈向上層虛擬了多台機器,配置了吊鏈結構的linux主機如果說只有一塊網卡,那麼外部會認為它有多塊網卡,對於內部,應用層會認為彼此在不同的主機 上,這就是效果。
除了上面大體的介紹之外,還有很多細節,吊鏈在主鏈上是沒有主次的,子鏈除了第一個節點其它節點也不分主次,都是平行的關系,但是子鏈中的第一個節點總是 鏈接在主鏈中,它們攜帶的地址就是primary地址,它們下面隸屬的子鏈攜帶的地址就是這個primary地址的secondary地址,如此看來,一 旦主鏈上一個節點被刪除了,那麼它的子鏈也將不復存在,所謂皮之不存毛將焉附。但是這種策略總是顯得不是那麼優美,因為父親犯錯,兒子也要受連累,這在現 代社會早就不時行了,那麼就需要改變機制了,因此linux中特意有了一個選項,就是當一個primary地址被刪除時,如果它有secondary地址 的話,那麼它的第一個secondary地址(長子)繼承被刪除的primary地址的位置成為primary地址,這樣就顯得很合理了,要不然在刪除 primary地址的時候,如果有程序用secondary地址,那麼要麼延遲刪除,要麼程序崩潰,採用自動提升策略的話就不會出現問題。
至於說IP aliases,那是以前版本有的了,就是一個實現問題,解決的問題和現在的secondary IP機制一樣,它主要就是在物理網卡名字後面加上後綴從而成為虛擬網路介面,本質上和secondary IP機制沒有區別,區別就是IP aliases顯得不是那麼直觀,而secondary IP卻是真正讓應用看到了一個網卡的多個地址,比如你要是用IP aliases的話,有的時候你總是會問eth0:0是什麼?我就曾經在內核裡面拚命找eth0:0這個網路設備的注冊代碼,都要瘋掉了也沒有找到,其實 我並不是很傻,但是我卻因為那個該死的名字作出了傻事。
下面就可以看看linux內核的實現代碼了,首先弄明白一些數據結構,最重要的就是net_device,其次就是in_device,然後就是in_ifaddr,明白了這三個數據結構,一切就明白了,這是真的。
structnet_device
{
...
void*ip_ptr;//指向一個in_device結構,這欄位從net_device中分離表明一個網卡可以支持多種網路層協議的
...
}
structin_device
{
structnet_device*dev;//指向它隸屬的net_device,也就是網卡
atomic_trefcnt;//引用計數
intdead;
structin_ifaddr*ifa_list;//所有的ip地址鏈表
...
};
structin_ifaddr//代表一個ip地址
{
structin_ifaddr*ifa_next;//上面的in_device中的ifa_list欄位就是靠這個欄位連成鏈的
structin_device*ifa_dev;//回指in_device結構
structrcu_headrcu_head;
u32ifa_local;//ip地址
u32ifa_address;
u32ifa_mask;//掩碼
u32ifa_broadcast;//廣播地址
u32ifa_anycast;
unsignedcharifa_scope;
unsignedcharifa_flags;//只有IFA_F_SECONDARY標志,因為除了這個就是primary地址了
unsignedcharifa_prefixlen;
charifa_label[IFNAMSIZ];//名字,在ipaliases時代,它就可能是ethx:y的形式,在secondaryip時代,它統一就是ethx
};
注 意,上面的結構並沒有將linux網卡的ip地址結構表示為吊鏈結構,所謂的吊鏈結構只是邏輯上的,在數據結構上,一個網卡所有的ip地址全部都在 ifa_list中被鏈接成一個線性的鏈表,至於是primary地址還是secondary地址就看in_ifaddr的ifa_flags欄位了。每 當有新的地址被設置的時候,inet_insert_ifa總是被調用,linux為何沒有在代碼上將ip地址表示為吊鏈結構呢?我也不知道,個人感覺一 個net_device帶有一個primary ip鏈表,然後每個primary ip節點帶有一個secondary ip鏈表,這樣會更好一些的,我覺得inet_insert_ifa實現的十分拙劣。添加地址可以通過兩個用戶空間程序搞定,一個是ifconfig,另 一個是ip addr add,ifconfig是基於ioctl進行地址添加的,而ip程序是基於netlink進行地址添加的,不管哪一種方式都可以達到目的,現在就可以看 看另一個問題了:為何用ip addr add添加的ip地址用ifconfig看不到,而ifconfig設置的地址ip addr show卻是可以看到。這個問題通過看代碼一眼就可以明白,在ifconfig獲得ip地址的時候,代碼:
for(ifap=&in_dev->ifa_list;(ifa=*ifap)!=NULL;ifap=&ifa->ifa_next)
{
if(!strcmp(ifr.ifr_name,ifa->ifa_label)&&sin_orig.sin_addr.s_addr==ifa->ifa_address)
{
break;
}
}
取 的是這個被找到的ifa的ip地址,而我們知道,所有的ifa鏈接成一個線性鏈表,那麼找到了第一個就不會再往後走了,因此只能得到一個結果,就是鏈表最 前面的那個,而ip add show就不同了,具體在函數inet_mp_ifaddr中實現,該函數遍歷所有的ifa,並且傳到用戶空間緩沖區。這里可以做一個實驗:首先用 ip addr add添加幾個不在同一個網段的primary ip地址,然後再ifconfig一個和前面的ip都不在一個網段的ip,然後可以用ifconfig查看一下,發現不是剛剛用ifconfig設置進去 的那個ip,而是用ip addr add添加進去的,這就說明ifconfig永遠都是取的ifa鏈表最前面的那一個,還有一點要注意,就是如果你用ip addr add添加了很多的secondary ip地址,那麼恰好你用ifconfig設置的ip地址和那些secondary ip在一個網段,那麼所有的secondary ip都將被刪除,這些都是sencondary ip的規范決定的,而且在代碼中也有體現。另外還要注意,路由表的表項都是基於primary ip的,因為所有的操作都是以primary ip為主的,比如在添加路由的時候:
voidfib_add_ifaddr(structin_ifaddr*ifa)
{
structin_device*in_dev=ifa->ifa_dev;
structnet_device*dev=in_dev->dev;
structin_ifaddr*prim=ifa;
...
if(ifa->ifa_flags&IFA_F_SECONDARY){//如果ifa是個sencondary地址,那麼就找到它隸屬的primary地址後然後以這個primary為主進行設置
prim=inet_ifa_byprefix(in_dev,prefix,mask);
if(prim==NULL){
printk(KERN_DEBUG"fib_add_ifaddr:bug:prim==NULL/n");
return;
}
}
fib_magic(RTM_NEWROUTE,RTN_LOCAL,addr,32,prim);//添加進路由表
...
}
到 此為止我們知道了不少東西,最重要的就是linux中網卡ip地址的吊鏈結構以及這么設計的好處,另外就是設置ip地址的方式有ioctl和 netlink。其實網卡擁有多個ip並不會帶來什麼沖突,本質上ip和網卡沒有什麼關系,它們唯一的關系就是靠網路分層模型聯系在一起的,細節上就是靠 路由聯系在一起的,比如我添加路由的時候指定了一個目的地址和下一跳ip地址以及一個網卡出口,那麼內核會根據提供的目的地址將路由插在合式的位置,然後 將nh的網路設備設置為你提供的網卡出口,等到傳輸數據的時候就會查找路由從而找到出口,就是這么簡單,你自己手動設置的路由可以隨意設置,即使完全錯誤 內核也會將之加入路由表的,還有一種路由是內核自動生成的,就是在網卡剛剛up的時候,這時通過網卡的net_device找到其in_device然後 找到其ip地址,這樣的路由稱為鏈路路由。
通過secondary IP機制,你可以認為你的機器有很多網卡,對於應用,監聽同一埠的應用會認為它們在區域網中不同的機器上,你可以隨意使用這些ip地址而不會發生混亂,路由和底層的arp會處理好這一切,當然前提是你將路由設置對。
附: 用戶空間有ifup/ifdown,/sbin/ip,ifconfig,還有netplugd守護進程,這些有何關系嗎?這中間ip程序是最基本的,沒 有任何策略,策略就是參數指定,要麼就是別的程序調用它,而netplugd就是一個監控守護進程,通過netlink監控網卡狀態,然後根據不同的監控 結果調用/etc/netplug.d/netplug腳本,進而可能調用ifup/ifdown腳本,而後者就是腳本,其中會調用ifup-eth腳 本,最終整理好參數後調用ip程序(典型的就是:ip link set eth0 up/down),當然ip程序完全可以自己調用,比如ip addr add以及ip route add等等,而ifconfig沒有那麼繞圈子,就是通過ioctl進行設置,可以通過strace來觀察。這其中奧妙大了去了,說白了就是策略和機制分 離,另外還體現出linux中的很多功能都是很小的程序組合而成的。
Linux的ip地址的吊鏈結構以及ip地址的定址特性(詳見《關於IP網段間互訪的問題—路由是根本》)充分說明了linux的協議棧實現多麼的完美,完全符合分層和封裝模型,使得下層的邏輯和上層的邏輯完全解除耦合,也就是說ip層完全不依賴鏈路層以及物理層的物理布局,最後記住,ip層事情比如定址路由只由ip層實現,之所有有鏈路層發現的路由,完全是為了方便。
❸ 圖說智慧型手錶風流史,來看 Apple Watch 的前輩們
虎嗅網:羅馬不是一天建成的,智能手錶也不是最近才發明的。
關於AppleWatch的討論正酣,一定有越來越多的廠商和創業團隊也在打智能手錶的主意。
回顧下智能手錶的發展歷程,正是時候。
本文轉自網易科技,原標題為《買買買!智能手錶的風流史》,虎嗅編輯後發布。
蘋果公司在最近召開的春季發布會上公布了AppleWatch的細節信息以及具體的上市時間,與iPhone和iPad一樣,盡管AppleWatch是史上最受關注的新款智能手錶,但蘋果卻並不是首家推出此類產品的廠商,而已經推出多款智能手錶的三星和索尼也不是。實際上,首款智能手錶要追溯到1927年,同時在上世紀80年代和90年代已經出現過一次較大規模的熱潮。
這里結合外媒的報導,盤點了智能手錶發展史上比較有代表性的19款重要產品,正是有了這些產品的存在,才讓AppleWatch的成功成為一種可能。
(1)PlusFour腕上路線指引器
發布時間:1927年
產品簡介:早在上世紀的20年代,GPS還沒有出現,但這款最早的「智能手錶」仍然能夠幫助佩戴者識別從A到B的具體路線,當然,其所採用的不過時間一個插槽式地圖盒放置在手腕上,通過旋鈕來手動調節要顯示的內容。盡管這款無法顯示時間的「手錶」看起來非常簡單,但它的功能也確實非常有針對性,同時用戶完全不用考慮它的電池續航時間。
(2)Pulsar電子手錶
發布時間:1972年
產品簡介:知名美國手錶品牌漢密爾頓(Hamilton)在1972年(一說1971年)推出了世界上的首款數字式電子手錶Pulsar,這款手錶的表面鍍了一層18K黃金。Pulsar配備了一個LED屏幕,同時在查看時間時需要按下機身上的按鈕。這款在當時頗為先進的電子手錶要價2100美元,基本上也算是價格不菲了。
(3)精工電視手錶(TVWatch)
發布時間:1982年
產品簡介:這款手錶曾經在第13部007電影《八爪女》(Octopussy)中被詹姆斯·邦德佩戴,而它「智能」的地方在於通過連接一個適配器和一個接收盒,可以同時在屏幕上方顯示時間,而在下方顯示顆粒感比較強的電視圖像,所以這款在當時要價500英鎊的手錶實際上更像是一款能夠戴在手腕上的顯示器。
(4)精工Data-2000智能手錶
發布時間:1983年
產品簡介:這款手錶能夠存儲備忘錄(盡管只有兩條)和日歷,同時還可以充當計算器使用,當然此時你需要使用配套的鍵盤才能實現。日本手錶廠商精工在上世紀80年代推出了多款智能手錶,除了Data-2000之外,同年精工還推出了UC-2000、RC-1000、MemoDiary和UC-3000等智能手錶產品。
(5)Sinclair腕上收音機
發布時間:1985年
產品簡介:英國的Sinclair公司曾經憑借一款名為ZXSpectrum的8位個人電腦獲得巨大成功,隨後該公司聯合美國手錶廠商天美時(Timex)研發了一款比較奇葩的腕上收音機,這款產品由液晶手錶、壓電揚聲器和FM調諧器三個獨立部分組成,同時還有一個內置在卡扣上的電池倉。由於當時恰逢Sinclair公司遭遇財務危機,這款手錶並未走過原型期就被公司叫停,當時僅生產了11000塊。
(6)精工MessageWatch智能手錶
發布時間:1995年
產品簡介:這款手錶已經頗有智能手錶的范兒了,不僅能夠顯示來電者ID(通過FM調頻信號),同時還支持體育比賽、股票價格和天氣預報等信息更新,這些功能與如今的GoogleNow比較相似,只不過它出現在20年前,同時其屏幕也不過是一塊非常普通的單色屏幕。
(7)百年靈緊急求救腕錶(EmergencyWatch)
發布時間:1995年
產品簡介:瑞士手錶品牌百年靈(Breitling)的這款腕錶可以在90海里范圍內發送緊急求救信號,讓救援人員確定遇險對象的所在位置,該手錶曾在2003年幫助兩名英國飛行員順利脫險(其所駕駛的直升機在南極區域墜毀)。2013年,百年靈對該產品系列進行了更新,發布了EmergencyII,售價9000英鎊。
(8)Linux腕錶
發布時間:1998年
產品簡介:「可穿戴計算之父」史蒂夫·曼恩(SteveMann)在1998年打造了首款由Linux驅動的智能手錶產品,IBM在兩年後生產出了這款手錶的原型機。「這款手錶被設計用來與電腦、手機和其它無線設備進行無線通訊,同時,該手錶還具備查看電子郵件和直接接收尋呼機類信息的功能,」當年的材料這樣寫道,「未來該手錶還將配備高清屏幕,同時支持應用程序的安裝和運行,此外還能充當互聯網服務的接入窗口,包括最新的天氣信息、交通狀況、股市變化、體育比賽結果等等。」看到這里,或許你就知道曼恩為何被成為是「可穿戴計算之父」了。
(9)FossilPalmPilot智能手錶
發布時間:2002年
產品簡介:美國時尚生活品牌Fossil最近透露稱要重新進軍可穿戴市場,計劃聯合英特爾推出智能手錶產品。該公司曾在12年前推出過一款名為PalmPilot的智能手錶,該手錶曾在2002年榮獲當年的Cox展會「最佳產品」獎項,PalmPilot配備了解析度為160*160的屏幕和2MB的存儲空間,同時還內置了多款Palm應用,包括地址薄、記事本、待辦事項和計算器,此外需要指出的是,這款手錶的操作系統採用了可視化風格,這也是該產品的一大亮點。
(10)微軟SPOT設備
發布時間:2003年
產品簡介:最近有傳言稱微軟目前正在研發一款全新的可穿戴設備,但在十多年前,微軟已經就已經在聯合西鐵城、天美時、Fossil和松拓等手錶廠商聯合研發了採用「智能個人對象技術」(SmartPersonalObjectTechnology,簡稱SPOT」的設備,不過微軟在2008年叫停了該項目,而其所提出的每年59美元的服務更新訂閱費也並未真正獲得消費者的認可。
(11)佳明ForerunnerGPS腕錶
發布時間:2003年
產品簡介:美國GPS廠商佳明在GPS運動腕錶領域一直位居前列,該公司早在10多年前就推出了手錶產品,初代Forerunner腕錶雖然看起來相當笨拙,但是卻已經具備了測量速度、距離、步幅和熱量消耗等功能,這也為以後的Forerunner系列腕錶的強大功能打下了堅實基礎。此外,這款產品的電量由兩節AAA電池供應,可以持續使用14個小時的時間。
(12)Nike+Fuelband運動手環
發布時間:2012年
產品簡介:毫不誇張地說,Nike+Fuelband運動手環是一款取得巨大成功的可穿戴產品,它可以追蹤佩戴者一整天的活動情況,同時還支持藍牙同步功能。2013年耐克還對該產品進行了更新,加入了環境光功能,方便佩戴者的光線較暗的情況下查看相應地信息。不過可惜的是,耐克在2014年年初解散了Fuelband硬體團隊,轉而關注軟體應用服務。
(13)索尼SmartWatch智能手錶
發布時間:2012年
產品簡介:初代索尼SmartWatch智能手錶實際上是Xperia智能手機的配套設備,該手錶運行一個變種的Android,配備了1.3英寸的OLED屏幕,這款產品在當年深受各大科技媒體的喜愛,盡管它經常出現毫無徵兆的系統奔潰情況。索尼隨後在2013年推出的SmartWatch2獲得了巨大成功,而其第三代產品、搭載AndroidWear的SmartWatch3已經在IFA2014上亮相。
(14)Pebble智能手錶
發布時間:2013年
產品簡介:到目前為止,Pebble智能手錶仍然是眾籌平台Kickstarter上最為成功的項目,這款產品重新將智能手錶的功能拉回到正確的發展軌道上來,把通知推送功能放在最為重要的位置上,除了該功能之外,Pebble還能夠充當智能手機或GoPro運動相機的遠程式控制制器,目前Pebble應用商店裡有超過1000款應用,基本上能夠滿足大部分用戶的需求。
(15)三星GalaxyGear智能手錶
發布時間:2013年
產品簡介:在IFA2013上亮相的GalaxyGear是三星進軍智能手錶市場的開山之作,如今三星已經推出了6款智能手錶產品,很顯然,三星非常希望在這一群雄紛爭的領域中獲得成功,但就目前情況來看,三星要想獲得像蘋果粉絲對AppleWatch那樣的追捧,還有很長的一段路要走。
(16)三星GearFit智能手環
發布時間:2014年產品簡介:如果說GalaxyGear為三星打開了可穿戴設備市場,那麼GearFit則是一款讓三星贏得滿堂彩的手環產品,這款在MWC2014發布的產品一經亮相就憑借其獨特的OLED曲面屏幕成為展會的亮點之一。
(17)Moto360智能手錶
發布時間:2014年產品簡介:2014年3月,谷歌在I/O大會上發布了可穿戴操作系統AndroidWear,在當時發布的三款AndroidWear設備中,Moto360無疑是關注度最高的一款,這款配備圓形表盤、售價199英鎊的智能手錶到現在為止還被認為是AppleWatch的主要競爭對手之一。
(18)三星GearS智能手錶
發布時間:2014年產品簡介:三星GearS內置了3G模塊,所以其可以在不與智能手機配對的情況下獨立使用,這款產品反映出三星對智能手錶市場的認知已經比較深厚,除了內置3G模塊之外,其所採用的2英寸的SuperAMOLED曲面屏幕、高達360*480的解析度都讓人眼前一亮。
(19)AppleWatch智能手錶
上市時間:2015年
產品簡介:2014年9月,蘋果在新款iPhone的發布會上推出了傳聞已久的智能手錶產品AppleWatch,關於這款產品的設計、配置和售價已無需贅述,這款定於4月24日正式開售的智能手錶自誕生之日起就備受關注,所以不管其未來能否獲得成功,都將會是智能手錶發展史上濃墨重彩的一筆。
你或許會喜歡
跟回合制游戲說掰~掰~不再無聊的手游在這里
❹ linux下裡面如何獲取網卡的實時網速
#include <time.h>
#include "tspeed.h"
int main ()
{
struct if_speed ndev;
int ret = 0;
bzero(&ndev,sizeof(ndev));
sprintf(ndev.ifs_name,"eth0");
ndev.ifs_us = 100000;
printf("Get %s Speed",ndev.ifs_name);
#if 1
ret = get_if_speed(&ndev);
if(ret < 0)
printf("[Fail]\n");
else
printf("[OK]\n");
float ispeed ,ospeed;
while(1){
time_t *timep = malloc(sizeof(*timep));
time(timep);
char *s = ctime(timep);
ispeed = ndev.ifs_ispeed * 1.0/(ndev.ifs_us/1000 * 0.001);
ospeed = ndev.ifs_ospeed * 1.0/(ndev.ifs_us/1000 * 0.001);
#if 0
printf("%s: Up Speed: %fMB/s || Down Speed: %fMB/s\r",
ndev.ifs_name,ispeed/(1024.0*1024.0),ospeed/(1024.0*1024.0));
#endif
sleep(3);
#if 1
printf("*****************************************************\n");
printf("*****************************************\n");
printf("***************************\n");
printf("*************\n");
printf("Time is %s || Down Speed: %fKB/s\n",s,ospeed/(1024.0));
#endif
get_if_speed(&ndev);
}
#endif
return 0;
} /* ----- End of main() ----- */
----------------------------------------------------------------------------
#include "tspeed.h"
int get_if_dbytes(struct if_info* ndev)
{
assert(ndev);
struct ifaddrs *ifa_list = NULL;
struct ifaddrs *ifa = NULL;
struct if_data *ifd = NULL;
int ret = 0;
ret = getifaddrs(&ifa_list);
if(ret < 0) {
perror("Get Interface Address Fail:");
goto end;
}
for(ifa=ifa_list; ifa; ifa=ifa->ifa_next){
if(!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
continue;
if(ifa->ifa_data == 0)
continue;
ret = strcmp(ifa->ifa_name,ndev->ifi_name);
if(ret == 0){
ifd = (struct if_data *)ifa->ifa_data;
ndev->ifi_ibytes = ifd->ifi_ibytes;
ndev->ifi_obytes = ifd->ifi_obytes;
break;
}
}
freeifaddrs(ifa_list);
end:
return (ret ? -1 : 0);
}
int get_if_speed(struct if_speed *ndev)
{
assert(ndev);
struct if_info *p1=NULL,*p2=NULL;
p1 = (struct if_info *)malloc(sizeof(struct if_info));
p2 = (struct if_info *)malloc(sizeof(struct if_info));
bzero(p1,sizeof(struct if_info));
bzero(p2,sizeof(struct if_info));
strncpy(p1->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));
strncpy(p2->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));
int ret = 0;
ret = get_if_dbytes(p1);
if(ret < 0) goto end;
usleep(ndev->ifs_us);
ret = get_if_dbytes(p2);
if(ret < 0) goto end;
ndev->ifs_ispeed = p2->ifi_ibytes - p1->ifi_ibytes;
ndev->ifs_ospeed = p2->ifi_obytes - p1->ifi_obytes;
end:
free(p1);
free(p2);
return 0;
}
------------------------------------------
#ifndef __TSPEED_H__
#define __TSPEED_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <error.h>
#include <ifaddrs.h>
#include <net/if.h> /* for ifconf */
#include <linux/sockios.h> /* for net status mask */
#include <netinet/in.h> /* for sockaddr_in */
#include <sys/socket.h>
#include <sys/ioctl.h>
/* For "open" function */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct if_data
{
/* generic interface information */
u_long ifi_opackets; /* packets sent on interface */
u_long ifi_ipackets; /* packets received on interface */
u_long ifi_obytes; /* total number of octets sent */
u_long ifi_ibytes; /* total number of octets received */
};
struct if_info
{
char ifi_name[16];
unsigned long ifi_ibytes;
unsigned long ifi_obytes;
};
struct if_speed
{
char ifs_name[16];
unsigned long ifs_ispeed;
unsigned long ifs_ospeed;
unsigned long ifs_us;
};
int get_if_dbytes(struct if_info *ndev);
int get_if_speed(struct if_speed *ndev);
#endif
------------------------
純手打 代碼都給你了
❺ sublime 列編輯的功能求助
Preferences.sublime-settings文件://Whileyoucaneditthisfile,it』sbesttoputyourchangesin//逗User/Preferences.sublime-settings地,.////,for//example,inPackages/python/Python.sublime-settingsforpythonfiles.{////主題文件的路徑逗color_scheme地:逗Packages/ColorScheme–Default/Monokai.tmTheme地,//Notethatthefont_faceandfont_sizeareoverridenintheplatform//specificsettingsfile,forexample,逗Preferences(Linux).sublime-settings地.//Becauseofthis,:youmustsetthem//inyourUserFilePreferences.//設置字體和大小,必須在Settings-User里重寫,這里設置沒有任何效果逗font_face地:逗Consolas地,逗font_size地:12,//Validoptionsare逗no_bold地,逗no_italic地,逗no_antialias地,逗gray_antialias地,//逗subpixel_antialias地and逗no_round地(OSXonly)//字體選項:no_bold不顯示粗體字,no_italic不顯示斜體字,no_antialias和no_antialias關閉反鋸齒//subpixel_antialias和no_round是OSX系統獨有的逗font_options地:[],////在文字上雙擊會全選當前的內容,如果裡面出現以下字元,就會被截斷逗word_separators地:逗./\\()\地『-:,.;~!@#$%^&*|+=[]{}`~?地,////是否顯示行號逗line_numbers地:true,////是否顯示行號邊欄逗gutter地:true,////行號邊欄和文字的間距逗margin地:4,////是否顯示代碼折疊按鈕逗fold_buttons地:true,////不管滑鼠在不在行號邊欄,代碼折疊按鈕一直顯示逗fade_fold_buttons地:true,////列顯示垂直標尺,在中括弧里填入數字,寬度按字元計算逗rulers地:[],////是否打開拼寫檢查逗spell_check地:false,////Tab鍵製表符寬度逗tab_size地:4,////設為true時,縮進和遇到Tab鍵時使用空格替代逗translate_tabs_to_spaces地:false,//Iftranslate_tabs_to_spacesistrue,use_tab_stopswillmaketaband//backspaceinsert/deleteuptothenexttabstop//translate_tabs_to_spaces設置為true,Tab和Backspace的刪除/插入作用於製表符寬度//否則作用於單個空格逗use_tab_stops地:true,//.spacesonload//false時禁止在載入的時候檢測製表符和空格逗detect_indentation地:true,////按回車時,自動與製表位對齊逗auto_indent地:true,//Makesautoindentalittlesmarter,e.g.,byindentingthenextline//afteranifstatementinC.Requiresauto_indenttobeenabled.//針對c語言的逗smart_indent地:false,//.Requires//auto_indenttobeenabled.//需要啟用auto_indent,第一次打開括弧縮進時插入空格看(沒測試出來效果…)逗indent_to_bracket地:true,//Trimswhitespaceaddedbyauto_//line.//顯示對齊的白線是否根據回車、tab等操作自動填補逗trim_automatic_white_space地:true,//.//Maybesettotrue,false,or逗auto地,whereitwillbedisabledfor//sourcecode,andotherwiseenabled.//是否自動換行,如果選auto,需要加雙引號逗word_wrap地:false,////windowwidth//設置窗口內文字區域的寬度逗wrap_width地:0,////level//防止被縮進到同一級的字換行逗indent_subsequent_lines地:true,////如果沒有定義過,則文件居中顯示(比如新建的文件)逗draw_centered地:false,//Controlsautopairingofquotes,bracketsetc//自動匹配引號,括弧等逗auto_match_enabled地:true,//Wordlisttouseforspellchecking//拼寫檢查的單詞列表路徑逗dictionary地:逗Packages/Language–English/en_US.dic地,//.//逗minimapBorder地keyin//thecolorscheme//代碼地圖的可視區域部分是否加上邊框,邊框的顏色可在配色方案上加入minimapBorder鍵逗draw_minimap_border地:false,//Ifenabled,//突出顯示當前游標所在的行逗highlight_line地:false,//Validvaluesare逗smooth地,逗phase地,逗blink地,逗wide地and逗solid地.//設置游標閃動方式逗caret_style地:逗smooth地,////是否特殊顯示當前游標所在的括弧、代碼頭尾閉合標記逗match_brackets地:true,//Settofalseifyou』//nexttoone//設為false時,只有游標在括弧或頭尾閉合標記的兩端時,match_brackets才生效逗match_brackets_content地:true,//.Thisonlytakeseffectif//match_bracketsistrue//是否突出顯示圓括弧,match_brackets為true生效逗match_brackets_square地:false,//.Thisonlytakeseffectif//match_bracketsistrue//是否突出顯示大括弧,match_brackets為true生效逗match_brackets_braces地:false,//.Thisonlytakeseffectif//match_bracketsistrue//是否突出顯示尖括弧,match_brackets為true生效逗match_brackets_angle地:false,////html和xml下突出顯示游標所在標簽的兩端,影響HTML、XML、CSS等逗match_tags地:true,////全文突出顯示和當前選中字元相同的字元逗match_selection地:true,//,inpixels//設置每一行到頂部,以像素為單位的間距,效果相當於行距逗line_padding_top地:1,//,inpixels//設置每一行到底部,以像素為單位的間距,效果相當於行距逗line_padding_bottom地:1,//.//OnOSX,,so//you』.//設置為false時,滾動到文本的最下方時,沒有緩沖區逗scroll_past_end地:true,////orlastline.//OnOSX,,so//you』.//控制向上或向下到第一行或最後一行時發生什麼(沒明白也沒試出來)逗move_to_limit_on_up_down地:false,//Setto逗none地toturnoffdrawingwhitespace,逗selection地todrawonlythe//whitespacewithintheselection,and逗all地todrawallwhitespace//按space或tab時,實際會產生白色的點(一個空格一個點)或白色的橫線(tab_size設置的製表符的寬度),選中狀態下才能看到//設置為none時,什麼情況下都不顯示這些點和線//設置為selection時,只顯示選中狀態下的點和線//設置為all時,則一直顯示逗draw_white_space地:逗selection地,//.////thecorresponding.tmThemefile,andspecifyingthecolors逗guide地,//逗activeGuide地and逗stackGuide地//製表位的對齊白線是否顯示,顏色可在主題文件里設置(guide,activeGuide,stackGuide)逗draw_indent_guides地:true,//,validoptionsare//逗draw_normal地and逗draw_active地.draw_activewilldrawtheindent//.//製表位的對齊白線,draw_normal為一直顯示,draw_active為只顯示當前游標所在的代碼控制域逗indent_guide_options地:["draw_normal"],////為true時,保存文件時會刪除每行結束後多餘的空格逗trim_trailing_white_space_on_save地:false,////characterwhensaving//為true時,保存文件時游標會在文件的最後向下換一行逗ensure_newline_at_eof_on_save地:false,////orapplication//切換到其它文件標簽或點擊其它非本軟體區域,文件自動保存逗save_on_focus_lost地:false,//』tbedeterminedautomatically.//ASCII,UTF-8andUTF-.//編碼時不能自動檢測編碼時,將自動檢測ASCII,UTF-8和UTF-16逗fallback_encoding地:逗Western(Windows1252)地,//,andfilesopenedwithanundefined//encoding(e.g.,plainasciifiles).Ifafileisopenedwithaspecific//encoding(),thissettingwillbe//ignored,//with.//默認編碼格式逗default_encoding地:逗UTF-8″,////包含空位元組的文件被打開默認為十六進制逗enable_hexadecimal_encoding地:true,//Determineswhatcharacter(s).//Validvaluesare『system』(whatevertheOSuses),『windows』(CRLF)and//『unix』(LFonly).//每一行結束的時候用什麼字元做終止符逗default_line_ending地:逗system地,//Whenenabled,.//Whendisabled,.//Shift+_completionis//enabled.//設置為enabled時,在一個字元串間按Tab將插入一個製表符//設置為true時,按Tab會根據前後環境進行代碼自動匹配填補逗tab_completion地:true,//.//代碼提示逗auto_complete地:true,//.//代碼提示的大小限制逗auto_complete_size_limit地:4194304,//Thedelay,inms,///projectbasis.逗folder_exclude_patterns地:[".svn",".git",".hg","CVS"],逗file_exclude_patterns地:["*.pyc","*.pyo","*.exe","*.dll","*.obj","*.o","*.a","*.lib","*.so","*.dylib","*.ncb","*.sdf","*.suo","*.pdb","*.idb",".DS_Store","*.class","*.psd","*.db"],//,butwon』tbeincludedin//GotoAnythingorFindinFiles逗binary_file_patterns地:["*.jpg","*.jpeg","*.png","*.gif","*.ttf","*.tga","*.dds","*.ico","*.eot","*.pdf","*.swf","*.jar","*.zip"],//Listanypackagestoignorehere.,//.//刪除你想要忽略的插件,需要重啟逗ignored_packages地:["Vintage"]}
❻ 在Linux中 if [ $ !=0 ] then 的含義
ifthen間的是邏輯表達式,不是賦值表達式。c語言:if(a(i,j)==0)vb6:ifa(i,j)=0thenIfA(i,j)=0ThenA(i,j)=k這句的意思是如果A(i,j)=0,那麼給A(i,j)賦值K
❼ C語言如何獲取嵌入式linux網卡上的mac地址
全對應的
getmacaddress.c
#include<stdio.h>
#ifdefined(WIN32)||(!defined(__GNUC__)&&!defined(__clang__))
#include<winsock2.h>
#include<iphlpapi.h>
#include<stdlib.h>
#pragmacomment(lib,"IPHLPAPI.lib")
#elifdefined(__linux__)
#include<string.h>//strncpy
#include<sys/ioctl.h>
#include<sys/socket.h>
#include<net/if.h>
#else
//bsd
#include<sys/types.h>//FreeBSDu_int
#include<ifaddrs.h>
#include<net/if.h>
#include<net/if_dl.h>
#include<net/if_types.h>
#endif
voidgetmacaddress(char*mac_address){
#ifdefined(WIN32)||(!defined(__GNUC__)&&!defined(__clang__))
PIP_ADAPTER_INFOpAdapterInfo;
PIP_ADAPTER_INFOpAdapter;
ULONGulOutBufLen=sizeof(IP_ADAPTER_INFO);
unsignedchar*addr;
mac_address[0]=0;
pAdapterInfo=(IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
if(!pAdapterInfo)return;
if(GetAdaptersInfo(pAdapterInfo,&ulOutBufLen)==ERROR_BUFFER_OVERFLOW){
free(pAdapterInfo);
pAdapterInfo=(IP_ADAPTER_INFO*)malloc(ulOutBufLen);
if(!pAdapterInfo)return;
}
if(GetAdaptersInfo(pAdapterInfo,&ulOutBufLen)==NO_ERROR){
pAdapter=pAdapterInfo;
if(pAdapter){
addr=pAdapter->Address;
sprintf(mac_address,"%02x:%02x:%02x:%02x:%02x:%02x",
addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]);
}
}
free(pAdapterInfo);
#elifdefined(__linux__)
mac_address[0]=0;
structifreq*ifr,*ifend;
structifreqifreq;
structifconfifc;
structifreqifs[16];
intfd;
unsignedchar*addr;
fd=socket(AF_INET,SOCK_DGRAM,0);
ifc.ifc_len=sizeof(ifs);
ifc.ifc_req=ifs;
if(ioctl(fd,SIOCGIFCONF,&ifc)<0){close(fd);return;}
ifend=ifs+(ifc.ifc_len/sizeof(structifreq));
for(ifr=ifc.ifc_req;ifr<ifend;ifr++){
if(ifr->ifr_addr.sa_family==AF_INET){
strncpy(ifreq.ifr_name,ifr->ifr_name,sizeof(ifreq.ifr_name));
if(ioctl(fd,SIOCGIFHWADDR,&ifreq)<0)continue;
addr=ifreq.ifr_hwaddr.sa_data;
sprintf(mac_address,"%02x:%02x:%02x:%02x:%02x:%02x",
addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]);
}
}
close(fd);
#else
//bsd
mac_address[0]=0;
structifaddrs*ifa_list,*ifa;
structsockaddr_dl*dl;
unsignedchar*addr;
if(getifaddrs(&ifa_list)<0)return;
for(ifa=ifa_list;ifa;ifa=ifa->ifa_next){
dl=(structsockaddr_dl*)ifa->ifa_addr;
if(dl->sdl_family==AF_LINK&&dl->sdl_type==IFT_ETHER){
addr=(unsignedchar*)LLADDR(dl);
sprintf(mac_address,"%02x:%02x:%02x:%02x:%02x:%02x",
addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]);
return;
}
}
freeifaddrs(ifa_list);
#endif
}
❽ 一台linux可支持多少tcp鏈接
這個文件是一個綜合性的問題。首先就tcp鏈接來說吧,主要體現在tcp的socket鏈接數上面,65535 應該是足夠用了,但是tcp連接11種狀態,不同不同狀態有可能有會話保持什麼的。這些暫且不說,現在tcp連接的還有Linux下文件的最大打開數量,流量帶寬等等。
優化:
1.ulimit -a 查看最大文件打開數量,然後修改
2.減少tcp長連接,或其他狀態鏈接,可以改下會話保持時間,主動自動關閉(不建議),重復使用tcp等。這個是在tcp鏈接數來進行考慮。
3.增多IP,增多埠,一個IP是這么多,那可以在一台Linux上綁定多個IP來增加鏈接數。等等
運維是一個大的課題,大家都是在學習中提高的,我的答案不一定正確,大家可以相互指正。更多Linux可以參考《Linux就該這樣學》,加油
❾ linux編程獲取本機的所有網口名稱
struct ifaddrs
{
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union
{
struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};