首先感謝各位兄弟姐妹們的耐心等待。本書預計在3月中旬上市發售。從今天開始,我將在博客中連載此書的一些內容。注意,此處連載的是未經出版社編輯的原始稿件,因此樣子會有些非專業。html
注意,以下是本章目錄,本文節選2.1-2.3以及2.5節。linux
爲了方便讀者深刻學習,本系列連載都會將做者研究過android
程中所學習的參考文獻列出來數據庫
第2章 深刻理解Netd編程
Netd是Android系統中專門負責網絡管理和控制的後臺daemon程序,其功能主要分三大塊:windows
由上述內容可知,Netd位於Framework層和Kernel層之間,它是Android系統中網絡相關消息和命令轉發及處理的中樞模塊。api
Netd的代碼量不大,難度較低,但其所涉及的相關背景知識卻比較多。本章對Netd的分析將從如下幾個方面入手:數組
最後,咱們將介紹Java Framework中的NetworkManagementService服務。緩存
提示:NsdService比較簡單,感興趣的讀者不妨閱讀做者的一篇博文」Android Says Bonjour」中的第2.2「NsdService介紹」一節。地址位於http://blog.csdn.net/innost/article/details/8629139。服務器
Netd進程由init進程根據init.rc的對應配置項[1]而啓動,其配置項如圖2-1所示。
圖2-1 Netd啓動配置參數
由圖2-1可知:
根據本章後續分析,讀者將會看到:
下面開始分析Netd進程。
Netd進程的入口函數是其main函數,代碼以下所示:
[-->main.cpp]
int main() {
CommandListener *cl;
NetlinkManager *nm;
DnsProxyListener *dpl;
MDnsSdListener *mdnsl;
ALOGI("Netd 1.0 starting");
//爲Netd進程屏蔽SIGPIPE信號
blockSigpipe();
//①建立NetlinkManager
nm = NetlinkManager::Instance();
//②建立CommandListener,它將建立名爲"netd"的監聽socket
cl = new CommandListener();
//設置NetlinkManager的消息發送者(Broadcaster)爲CommandListener。
nm->setBroadcaster((SocketListener *) cl);
//啓動NetlinkManager
nm->start();
......
//注意下面這行代碼,它爲本Netd設置環境變量ANDROID_DNS_MODE爲"local",其做用將在2.2.4節介紹
setenv("ANDROID_DNS_MODE", "local", 1);
//③建立DnsProxyListener,它將建立名爲"dnsproxyd"的監聽socket
dpl = new DnsProxyListener();
dpl->startListener();
//④建立MDnsSdListener並啓動監聽,它將建立名爲"mdns"的監聽socket
mdnsl = new MDnsSdListener();
mdnsl->startListener();
cl->startListener();
while(1) {
sleep(1000);
}
exit(0);
}
Netd的main函數很是簡單,主要是建立幾個重要成員並啓動相應的工做,這幾個重要成員分別是:
下面將分別討論這四位成員的做用。
NetlinkManager(之後簡稱NM)主要負責接收並解析來自Kernel的UEvent消息。其核心代碼在start函數中,以下所示。
[-->NetlinkManager.cpp::start]
int NetlinkManager::start() {
//建立接收NETLINK_KOBJECT_UEVENT消息的socket,其值保存在mUeventSock中
//其中,NETLINK_FORMAT_ASCII表明UEvent消息的內容爲ASCII字符串
mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII);
//建立接收RTMGPR_LINK消息的socket,其值保存在mRouteSock中
//其中,NETLINK_FORMAT_BINARY表明UEvent消息的類型爲結構體,故須要進行二進制解析
mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE, RTMGRP_LINK,
NetlinkListener::NETLINK_FORMAT_BINARY);
//建立接收NETLINK_NFLOG消息的socket,其值保存在mQuotaSock中
mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY);
return 0;
}
NM的start函數主要是向Kernel註冊了三個用於接收UEvent事件的socket,這三個UEvent[1][2]分別對應於:
提示:讀者可經過在Linux終端中執行man PF_LINK獲得有關NETLINK的詳細說明。
上述start函數將調用setupSocket建立用於接收UEvent消息的socket以及一個解析對象NetlinkHandler。setupSocket代碼自己比較簡單,此處就不擬展開分析。
下面來看NM及其家族成員,它們之間的關係如圖2-2所示。
圖2-2 NetlinkManager家族成員的類圖
由圖2-2可知:
下面來簡單瞭解下NetlinkHandler的onEvent函數,因爲其內部已針對不一樣屬性的NetlinkEvent進行了分類處理,故瀏覽這段代碼能加深對前文所述不一樣UEvent消息的做用的理解。
[-->NetlinkHandler.cpp::onEvent]
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
......
//處理對應NETLINK_KOBJECT_UEVENT和NETLINK_ROUTE的信息
if (!strcmp(subsys, "net")) {
int action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");//查找消息中攜帶的網絡設備名
if (action == evt->NlActionAdd) {
notifyInterfaceAdded(iface);//添加NIC(Network Interface Card)的消息
} else if (action == evt->NlActionRemove) {
notifyInterfaceRemoved(iface);//NIC被移除的消息
} else if (action == evt->NlActionChange) {
evt->dump();
notifyInterfaceChanged("nana", true);//NIC變化消息
} else if (action == evt->NlActionLinkUp) {//下面兩個消息來自NETLINK_ROUTE
notifyInterfaceLinkChanged(iface, true);//鏈路啓用(相似插網線)
} else if (action == evt->NlActionLinkDown) {
notifyInterfaceLinkChanged(iface, false);//鏈路斷開(相似拔網線)
}
} else if (!strcmp(subsys, "qlog")) {//對應NETLINK_NFLOG
const char *alertName = evt->findParam("ALERT_NAME");
const char *iface = evt->findParam("INTERFACE");
notifyQuotaLimitReached(alertName, iface);//當數據量超過預警值,則會收到該通知
} else if (!strcmp(subsys, "xt_idletimer")) {
//這個和後文的idletimer有關,用於跟蹤某個NIC的工做狀態,便是「idle」仍是「active」
//檢測時間按秒計算
int action = evt->getAction();
const char *label = evt->findParam("LABEL");
const char *state = evt->findParam("STATE");
if (label == NULL) {
label = evt->findParam("INTERFACE");
}
if (state)
notifyInterfaceClassActivity(label, !strcmp("active", state));
}
......
}
由上邊代碼可知:
圖2-3所示爲NetlinkHandler的工做流程。
圖2-3 NM工做流程圖
由圖2-3可知:
[1]關於init工做原理以及init.rc的分析方法,讀者可參考《深刻理解Android:卷1》第3章關於init進程的分析。
[1]讀者可參考《深刻理解Android:卷1》第9章關於Vold的分析。
Netd中第二個重要成員是CommandListener(之後簡稱CL),其主要做用是接收來自Framework層NetworkManageService的命令。從角色來看,CL僅是一個Listener。它在收到命令後,只是將它們轉交給對應的命令處理對象去處理。CL內部定義了許多命令,而這些命令都有較深的背景知識。本節擬以分析CL的工做流程爲主,而相關的命令處理則放到後文再集中分析。
CL中的圖2-4所示爲CL中的Command對象及對應的Controller對象。
圖2-4 CL中的命令及控制類
由圖2-4可知:
結合前面圖2-2中對NM家族成員的介紹,CL建立時,須要註冊本身支持的命令類。這部分代碼在其構造函數中實現,代碼以下所示:
[-->CommandListener::CommandListener構造函數]
CommandListener::CommandListener() :
FrameworkListener("netd", true) {
registerCmd(new InterfaceCmd());//註冊11個命令類對象
registerCmd(new IpFwdCmd());
registerCmd(new TetherCmd());
registerCmd(new NatCmd());
registerCmd(new ListTtysCmd());
registerCmd(new PppdCmd());
registerCmd(new SoftapCmd());
registerCmd(new BandwidthControlCmd());
registerCmd(new IdletimerControlCmd());
registerCmd(new ResolverCmd());
registerCmd(new FirewallCmd());
//建立對應的控制類對象
if (!sSecondaryTableCtrl)
sSecondaryTableCtrl = new SecondaryTableController();
if (!sTetherCtrl)
sTetherCtrl = new TetherController();
if (!sNatCtrl)
sNatCtrl = new NatController(sSecondaryTableCtrl);
if (!sPppCtrl)
sPppCtrl = new PppController();
if (!sSoftapCtrl)
sSoftapCtrl = new SoftapController();
if (!sBandwidthCtrl)
sBandwidthCtrl = new BandwidthController();
if (!sIdletimerCtrl)
sIdletimerCtrl = new IdletimerController();
if (!sResolverCtrl)
sResolverCtrl = new ResolverController();
if (!sFirewallCtrl)
sFirewallCtrl = new FirewallController();
if (!sInterfaceCtrl)
sInterfaceCtrl = new InterfaceController();
//其餘重要工做,後文再分析
}
因爲CL的間接基類也是SocketListener,因此其工做流程和NetlinkHandler相似。
爲了方便讀者理解,圖2-5給出了CL的工做流程圖:
圖2-5 CL的工做流程示意圖
DnsProxyListener和Android系統中的DNS管理有關。什麼是DNS呢?Android系統中DNS又有什麼特色呢?來看下文。
DNS是Domain Name System(域名系統)的縮寫。其主要目的是在域名和IP地址之間創建一種映射。簡單點說,DNS的功能相似於電話簿,它可將人名映射到相應的電話號碼。在DNS中,人名就是域名,電話號碼就是IP地址。域名系統的管理由DNS服務器來完成。全球範圍內的DNS服務器共同構成了一個分佈式的域名-IP數據庫。
對使用域名來發起網絡操做的網絡程序來講,其域名解析工做主要分兩步:
1)第一步工做就是須要將域名轉換成IP。因爲域名和IP的轉換關係存儲在DNS服務器上,因此該網絡程序要向DNS服務器發起請求,以獲取域名對應的IP地址。
2)DNS服務器根據DNS解析規則解析並獲得該域名對應的IP地址,而後返回給客戶端。在DNS中,每個域名和IP的對應關係被稱之爲一條記錄。客戶端通常會緩存這條記錄以備後續之用。
提醒:DNS解析規則比較複雜,感興趣的讀者可研究DNS的相關協議。
對軟件開發者來講,經常使用的域名解析socket API有兩個:
Android中,這兩個函數均由Bionic C實現。其代碼實現基於NetBSD的解析庫(resolver library),並通過一些修改。這些修改包括:
圖2-6所示爲三星Galaxy Note2中有關dns信息的示意圖。
圖2-6 net.dns設置示意圖
由圖2-6可知:
本節將介紹Android中getaddrinfo的實現,咱們將只關注Android對其作的改動。
[-->getaddrinfo.c::getaddrinfo]
int getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
......//getaddrinfo的正常處理
//Android平臺的特殊定製
if (android_getaddrinfo_proxy(hostname, servname, hints, res) == 0) {
return 0;
}
......//若是上述函數處理失敗,則繼續getaddrinfo的正常處理
return error
}
由上述代碼可知,Android平臺中的getaddrinfo會調用其定製的android_getaddrinfo_proxy函數完成一些特殊操做,該函數的實現以下所示:
[-->getaddrinfo.c::android_getaddrinfo_proxy]
static int android_getaddrinfo_proxy(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
.......
//取ANDROID_DNS_MODE環境變量。只有Netd進程設置了它
const char* cache_mode = getenv("ANDROID_DNS_MODE");
......
//因爲Netd進程設置了此環境變量,故Netd進程調用getaddrinfo的話,將不會採用這套定製的方法
if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
return -1;
}
//獲取本進程對應的DNS地址
snprintf(propname, sizeof(propname), "net.dns1.%d", getpid());
if (__system_property_get(propname, propvalue) > 0) {
return -1;
}
//創建和Netd中DnsProxyListener的鏈接,將請求轉發給它去執行
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
return -1;
}
......
strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd",
sizeof(proxy_addr.sun_path));
......//發送請求,處理回覆等
return -1;
}
由上述代碼可知:
下面來介紹DnsProxyListener(之後簡稱DPL),圖2-7所示爲其家族成員示意圖:
圖2-7 DPL家族示意圖
由圖2-7可知,DPL僅定義了兩個命令:
這個兩條命令的處理比較簡單,此處就不擬展開詳細的代碼。
爲方便讀者理解,咱們將給出調用序列圖,如圖2-8所示。
圖2-8 GetAddrInfoCmd處理流程示意圖
由圖2-8所示,GetAddrInfoHandler最終的處理仍是交由Bionic C的getaddrinfo函數來完成。根據前文所述,因爲Netd進程設置了ANDROID_DNS_MODE環境變量,故Netd調用的getaddrinfo將走正常的流程。這個正常流程就是Netd進程將向指定的DNS服務器發起請求以解析域名。
Android系統中,經過這種方式來管理DNS的好處是全部解析後獲得的DNS記錄都將緩存在Netd進程中,從而使這些信息成爲了一個公共的資源,最大程度內作到了信息共享。
2.2.5 MDnsSdListener分析
MDnsSd是Multicast DNS Service Discovery的簡稱,它和Apple公司的Bonjour技術有關,故本節將先介紹Apple Bonjour技術。
Bonjour是法語中的Hello之意。它是Apple公司爲基於組播域名服務(multicast DNS)的開放性零配置網絡標準所起的名字。使用Bonjour的設備在網絡中自動組播它們本身的服務信息並監聽其餘設備的服務信息,設備之間就像在打招呼,這也是該技術命名爲Bonjour的緣由。Bonjour使得局域網中的系統和服務即便在沒有網絡管理員的狀況下也很容易被找到。
舉一個簡單的例子:在局域網中,若是要進行打印服務,就必須先知道打印服務器的IP地址。此IP地址通常由IT部門的人負責分配,而後他還得全員發郵件以公示此地址。有了Bonjour之後,打印服務器本身會依據零配置網絡標準在局域網內部找到一個可用的IP並註冊一個打印服務,名爲「print service」之類的。當客戶端須要打印服務時,會先搜索網絡內部的打印服務器。因爲不知道打印服務器的IP地址,客戶端只能根據諸如"print service"的名字去查找打印機。在Bonjour的幫助下,客戶端最終能找到這臺註冊了「print service」名字的打印機,並得到它的IP地址以及端口號。
從Bonjour角度來看,該技術主要解決了三個問題:
Bonjour技術在Mac OS以及Itunes、Iphone上都獲得了普遍應用。爲了進一步推廣,Apple經過開源工程mdnsresponder將其開源出來。在Windows平臺上,它將生成一個後臺程序mdnsresponder。在Android平臺上(或者說支持POSIX的Linux平臺)它是一個名爲mdnsd的程序。不過,不管是mdnsresponder仍是mdnsd,應用開發者要作的僅僅是利用Bonjour的API向它們發起服務註冊、服務查詢和服務解析等請求並接收來自它們的處理結果。
下面咱們將介紹Bonjour API中使用最多的三個函數,它們分別是服務註冊、服務查詢和服務解析。理解這三個函數的功能也是理解MDnsSdListener的基礎。
使用Bonjour API必須包含以下的頭文件和動態庫,並鏈接到:
#include <dns_sd.h> //必須包含此頭文件
libmdnssd.so //連接到此so
Bonjour中,服務註冊的API爲DNSServiceRegister,原型以下:
DNSServiceErrorType DNSSD_API DNSServiceRegister
(
DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *name, /* may be NULL */
const char *regtype,
const char *domain, /* may be NULL */
const char *host, /* may be NULL */
uint16_t port, /* In network byte order */
uint16_t txtLen,
const void *txtRecord, /* may be NULL */
DNSServiceRegisterReply callBack, /* may be NULL */
void *context /* may be NULL */
);
該函數的解釋以下:
當客戶端須要搜索網絡內部特定服務時,須要使用DNSServiceBrowser API,其原型以下:
DNSServiceErrorType DNSSD_API DNSServiceBrowse
(
DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *regtype,
const char *domain, /* may be NULL */
DNSServiceBrowseReply callBack,
void *context /* may be NULL */
);
其中:
當客戶端想得到指定服務的IP和端口號時,須要使用DNSServiceResolve API,其原型以下:
DNSServiceErrorType DNSSD_API DNSServiceResolve
(
DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *name,
const char *regtype,
const char *domain,
DNSServiceResolveReply callBack,
void *context /* may be NULL */
);
其中:
MDnsSdListener對應的Framework層服務爲NsdService(Nsd爲Network Service Discovery的縮寫),它是Android 4.1新增的一個Framework層Service。該服務的實現比較簡單,故本書不擬詳細討論它。感興趣的讀者不妨首先閱讀SDK中關於NsdService的相關文檔。
提示:SDK中有一個基於Nsd技術開發的NsdChat例程,讀者也可先學習它的實現。相關文檔位置爲http://developer.android.com/training/connect-devices-wirelessly/nsd.html。
圖2-9所示爲MDnsSdListener的家族成員示意圖。
圖2-9 MDnsSdListener家族成員
由圖2-9可知:
下面將簡單介紹MDnsSdListener的運行過程,主要工做可分紅三步:
1)Netd建立MDnsSdListener對象,其內部會建立Monitor對象,而Monitor對象將啓動一個線程用於和mdnsd通訊,並接收來自Handler的請求。
2)NsdService啓動完畢後將向MDnsSdListener發送"start-service"命令。
3)NsdService響應應用程序的請求,向MDnsSdListener發送其餘命令,例如"discovery"等。Monitor將最終處理這些請求。
先來看第一步,當MDnsSdListener構造時,會建立一個Monitor對象,代碼以下所示:
[-->MDnsSdListener.cpp::Monitor:Monitor]
MDnsSdListener::Monitor::Monitor() {
mHead = NULL;
pthread_mutex_init(&mHeadMutex, NULL);
//建立兩個socket,用於接收MDnsSdListener對象的指令
socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
//建立線程,線程函數是threadStart,其內部會調用run
pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
}
Monitor的threadStart線程將調用其run函數,該函數經過poll方式偵聽包括mCtrlSocketPair在內的socket信息。這部分代碼屬於基本的Linux socket編程,本書不擬開展深刻討論。
當NsdService發送"start-service"命令後,Handler的runCommand將執行Monitor的startService函數,代碼以下所示:
[-->MDnsSdListener.cpp::Monitor:startService]
int MDnsSdListener::Monitor::startService() {
int result = 0;
char property_value[PROPERTY_VALUE_MAX];
pthread_mutex_lock(&mHeadMutex);
//MDNS_SERVICE_STATUS是一個字符串,值爲「init.svc.mdnsd」,在init.rc配置文件中,mdnsd是一個
//service,而「init.svc.mdnsd」將記錄mdnsd進程的運行狀態。
property_get(MDNS_SERVICE_STATUS, property_value, "");
if (strcmp("running", property_value) != 0) {
//若是mdnsd的狀態不爲"running",則經過設置「ctl.start」命令啓動mdnsd
property_set("ctl.start", MDNS_SERVICE_NAME);
//若是mdnsd成功啓動,則屬性值變成"running"
wait_for_property(MDNS_SERVICE_STATUS, "running", 5);
result = -1;
} else {
result = 0;
}
pthread_mutex_unlock(&mHeadMutex);
return result;
}
startService的實現比較有趣,它充分利用了init的屬性控制以啓動mdnsd進程。
當NsdService發送註冊服務請求時,Handler的serviceRegister函數將被調用,代碼以下所示:
[-->MDnsSdListener.cpp::Handler:serviceRegister]
void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,
const char *interfaceName, const char *serviceName, const char *serviceType,
const char *domain, const char *host, int port, int txtLen, void *txtRecord) {
Context *context = new Context(requestId, mListener);
DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);
port = htons(port);
......
DNSServiceFlags nativeFlags = 0;
int interfaceInt = ifaceNameToI(interfaceName);
//調用Bonjour API DNSServiceRegister,並註冊回調函數MDnsSdListenerRegisterCallback
DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt,
nativeFlags, serviceName, serviceType, domain, host, port,
txtLen, txtRecord, &MDnsSdListenerRegisterCallback, context);
if (result != kDNSServiceErr_NoError) {
.....//錯誤處理
}
//通知Monitor對象進行rescan,請讀者自行研究該函數
mMonitor->startMonitoring(requestId);
cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started", false);
return;
}
DNSServiceRegister內部將把請求發送給mdnsd去處理,處理的結果經過MDnsSdListenerRegisterCallback返回,該函數代碼以下所示:
[-->MDnsSdListener.cpp::MDnsSdListenerRegisterCallback]
void MDnsSdListenerRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
DNSServiceErrorType errorCode, const char *serviceName, const char *regType,
const char *domain, void *inContext) {
MDnsSdListener::Context *context =
einterpret_cast<MDnsSdListener::Context *>(inContext);
char *msg;
int refNumber = context->mRefNumber;
if (errorCode != kDNSServiceErr_NoError) {
......//錯誤處理
} else {
char *quotedServiceName = SocketClient::quoteArg(serviceName);
asprintf(&msg, "%d %s", refNumber, quotedServiceName);
free(quotedServiceName);
//將處理結果返回給NsdService
context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded,
msg,false);
}
free(msg);
}
提示 本節對Netd的工做流程進行了相關分析,這部分代碼相對簡單,處理流程也比較固定:
1)NM接收Kernel的UEvent消息,而後轉發給Framework層的客戶端。
2)CL、DPL以及MDnsSdListener接收來自客戶端的請求並處理它們。
惟一有趣的地方是Android中DNS的管理以及Apple Bonjour技術。感興趣的讀者不妨閱讀本章列出的參考資料以加深理解。
[1]此處結論來自bionic/libc/docs/OVERVIEW.txt文件,不過根據同目錄下CHANGES.txt的說明,resolv.conf將再也不使用
====================================================================================
=========================略略略略略略略略略略略略略略==================================
本章對Netd進行了詳細討論。相信讀者讀完此章的第一感覺必定是代碼這麼容易的模塊,居然涉及如此多複雜的背景知識。確實,這也是專題卷所述內容的核心特色。從代碼上看也許它們並不複雜,可是其背後的理論知識卻可能大有來頭。對於這些內容而言,代碼只是外在的表現形式,其核心必定在其背後的那些知識中。因此,讀者在閱讀專題卷的時候,必定要考察本身是否對背景知識有所掌握。
概況而言,Netd涉及的內容和網絡管理與控制有關,例如DNS、Apple Bonjour、利用iptables等工具實現NAT、防火牆、帶寬控制、流量控制、路由控制功能,以及USB綁定Wi-Fi、SoftAP等。請讀者在本節的參考資料一覽中找到並繼續研究本身感興趣的內容。
最後,咱們對NetworkManagementService進行了介紹。NMService的內容很是簡單。
[1] Linux man PF_NETLINK
本文檔是Linux系統中的幫助文檔。從整體上介紹了PF_NETLINK(AF_NETLINK)的做用和相關的數據結構。對熟手比較適用。
[2] http://www.linuxjournal.com/article/8498
「Manipulating the Networking Environment Using RTNETLINK」,這篇文章以RTNETLINK爲主要對象,介紹瞭如何利用它進行編程以操做網絡。此文寫得很是詳細,建議讀者深刻閱讀,甚至本身動手寫測試例子。
[3] http://baike.baidu.com/view/22276.htm
百度百科中關於dns的介紹,屬於入門級材料,不清楚的讀者能夠先了解相關知識。
[4] http://en.wikipedia.org/wiki/MDNS
維基百科中關於Multicast DNS的介紹。入門級材料,但包含的信息不是很全,須要跟蹤其中的連接才能對MDNS有全面瞭解。
「Introduction to Bonjour Overview」,蘋果開發網站上關於Bonjour基礎知識的入口,包含「About Bonjour」、「Bonjour API Architecture」等文檔。
「DNS Service Discovery Programming Guide」,蘋果開發網站關於NSD API的說明。
iptables的相關文檔很是多,雖然Linux也提供了幫助文檔(man iptables),但對新手來講該文檔實在不是學習的好資料。
[7] http://www.thegeekstuff.com/2011/01/iptables-fundamentals/
「Linux Firewall Tutorial: IPTables Tables, Chains, Rules Fundamentals」,這篇文章首先從原理上介紹瞭如何去理解iptables,而後介紹了相關的例子。筆者認爲它是iptables最好的入門資料。
[8] http://selboo.com.cn/post/721/
「iptables的相關概念和數據包的流程」,這篇文檔介紹了iptables中各個table及chain的處理順序,請讀者結合[7]來理解iptables。
[9] http://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
「Iptables 指南 1.1.19」,這篇文檔介紹的iptables版本比較舊(Android 4.2使用的iptables版本是1.4.11),但對iptables經常使用參數都有很是詳細的介紹。適合入門後的讀者進行深刻閱讀。
tc文獻的數量和難度遠大於iptables,此處精選幾個必讀文獻。
[10] http://linux-ip.net/articles/Traffic-Control-HOWTO/intro.html
「Traffic Control HOWTO」,理解traffic control的必讀文獻,覆蓋面很全,理論知識講解到位。難度稍大,須要仔細琢磨才能徹底理解。
[11] http://wenku.baidu.com/view/f02078db50e2524de5187e45.html
「TC(Linux下流量控制工具)詳細說明及應用實例」,百度文庫中的一篇文檔,篇幅雖然不長,但也作到了理論和實例結合。建議讀者先閱讀此文獻,而後再深刻研究[10]。
[12] http://fanqiang.chinaunix.net/a1/b1/20010811/0705001103.html
「在LINUX中實現流量控制器」,介紹TC的一篇博文,主要對tc的命令用法列舉了很多實例,屬於tc的實戰文章。建議放到最後閱讀。
[13] http://www.linuxfoundation.org/collaborate/workgroups/networking/ifb
這是筆者能找到的關於IFB設備最完整的資料,對IFB的使用、常規用法等進行了全方位的介紹。
ip命令比較簡單,這裏僅給出一篇文獻。
[14] http://blog.chinaunix.net/uid-24921475-id-2547198.html
Linux ip命令介紹
[15] Linux man netdevice
很是詳細的NetDevice編程介紹,建議讀者認真閱讀。
[16] http://www.cnblogs.com/iceocean/articles/1594488.html
「Linux策略路由」,中文文檔,知識面覆蓋較全,屬於入門級資料。
[17] http://www.policyrouting.org/PolicyRoutingBook/ONLINE/TOC.html
「Policy Routing With Linux」,這是一本完整的書籍(可見網管是一個複雜的工做)。我的感受[16]是參考[17]的學習總結。屬於高級閱讀材料,難度較大。
[18] http://www.ipsidixit.net/2012/08/09/ipv6-temporary-addresses-and-privacy-extensions/
「IPv6 temporary addresses and privacy extensions」,介紹Linux中IPv6臨時地址和privacy extensions方面的知識,知識覆蓋面較全。屬於入門資料。
[19] http://tldp.org/HOWTO/Text-Terminal-HOWTO.html
「Text-Terminal-HOWTO」,比較舊的資料,覆蓋面很是廣。讀者可僅閱讀本身想了解的章節。
[20] http://blog.tianya.cn/blogger/post_read.asp?BlogID=3616841&PostID=33399981
「Linux下tty/pty/pts/ptmx 詳解」,中文寫的好材料,還列出了其參考的文獻。最後,關於ptmx,讀者還可經過man ptmx得到如何用它進行編程的指導。
[21] http://tldp.org/HOWTO/PPP-HOWTO/
「Linux PPP HOWTO」,Linux HowTo系列的內容都簡單易懂。雖章節較多,但不少內容僅一兩句了事。可作入門參考。
[22] http://network.51cto.com/art/201009/223784.htm
「基礎解讀PPP協議」,中文文檔,一頁內容,主要介紹PPP框架性的內容。
[23] http://wenku.baidu.com/view/0c395f15866fb84ae45c8d4a.html
「ppp介紹」,百度文庫中的一個關於ppp的PPT。內容翔實,不只介紹了ppp協議的數據包,也從框架上介紹了ppp的工做流程。建議讀者首先閱讀此文獻。
[24] Linux man pppd
介紹pppd中各個選項的做用。
「用iptables實現NAT」,中文文檔,簡單易懂。
[26] http://en.wikipedia.org/wiki/Tethering
「Tethering」,維基百科中關於Tether的介紹,淺顯易懂,屬於普及型資料。
[27] http://msdn.microsoft.com/en-us/library/windows/hardware/gg463293.aspx
「Remote NDIS (RNDIS) and Windows」,MSDN文檔,很是翔實(不得不說微軟在文檔方面的工做真的是一絲不苟)。
[28] http://baike.baidu.com/view/7992.htm?subLemmaId=7992&fromenter=%A3%C4%A3%C8%A3%C3%A3%D0
百度百科中關於DHCP的解釋,入門資料。
[29] http://baike.baidu.com/view/6681631.htm
百度百科中關於DNSmasq的解釋。
[30] http://wenku.baidu.com/view/662b536b561252d380eb6ec1.html
關於DHCP協議中option字段的詳細介紹。
[31] 《802.11 無線網絡權威指南中文第二版》
讀者可先閱讀第1、2章中關於Wi-Fi技術中的一些基本概念,例如AP和Station。
[32] http://baike.baidu.com/view/2475889.htm
百度百科關於SoftAp的入門級介紹。
[33] 關於hostapd,讀者可利用man hostapd獲得各個選項的用法。
提示,讀者必須先安裝hostapd,而後才能查閱其幫助文檔。