首先感谢各位兄弟姐妹们的耐心等待。本书预计在3月中旬上市发售。从今天开始,我将在博客中连载此书的一些内容。注意,此处连载的是未经出版社编辑的原始稿件,所以样子会有些非专业。
注意,如下是本章目录,本文节选2.1-2.3以及2.5节。
为了方便读者深入学习,本系列连载都会将作者研究过
程中所学习的参考文献列出来
第2章 深入理解Netd
Netd是Android系统中专门负责网络管理和控制的后台daemon程序,其功能主要分三大块:
由上述内容可知,Netd位于Framework层和Kernel层之间,它是Android系统中网络相关消息和命令转发及处理的中枢模块。
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有全面了解。
[5] https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Introduction.html#//apple_ref/doc/uid/TP40002445-SW1
“Introduction to Bonjour Overview”,苹果开发网站上关于Bonjour基础知识的入口,包含“About Bonjour”、“Bonjour API Architecture”等文档。
[6] https://developer.apple.com/library/mac/#documentation/Networking/Conceptual/dns_discovery_api/Introduction.html#//apple_ref/doc/uid/TP30000964
“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中各个选项的作用。
[25] http://oa.jmu.edu.cn/netoa/libq/pubdisc.nsf/66175841be38919248256e35005f4497/7762e8e1056be98f48256e88001ef71d?OpenDocument
“用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,然后才能查阅其帮助文档。