TCP/IP FAQ

TCP/IP FAQ系列,以古老经典的4.4BSD-Lite实现为准,参考《TCP/IP协议详解》3卷 ,加入个人的思考理解,理清主干,不深究细枝末节,皆在总结基本原理和实现。
 本篇涵盖了数据链路层、ARP、RARP、IP、ICMP、TCP、UDP方面的问题与解答。

【Data Link】
1. 环回接口地址必须是127.0.0.1吗?
   形如127.x.x.x的A类IP都可作为环回接口的地址,但常用的是127.0.0.1。
2. 环回接口为什么没有输入处理?
   发送到环回接口的数据报实质上被送到网络层的输入队列中,因此数据报没有离开网络,也就不可能从链路上接收到目标地址为环回接口地址的数据帧,所以不存在输入处理。
3. SLIP、环回和以太网接口,三者有何不同?
   SLIP和环回接口没有链路层首部和硬件地址,环回接口没有输入处理,而以太网接口都有。
4. SLIP和以太网接口如何分用输入帧,环回接口如何分用输出分组?
   SLIP将帧直接放进IP输入队列中,以太网接口则根据帧类型字段放到对应的协议输入队列中,环回接口则按目的地址族放到对应的输入队列中。
5. 接口和地址有什么关联?
   一个接口的编址信息包括主机地址、广播地址和网络掩码,当内核初始化时,每个接口分配一个链路层地址,可以配置有多个相同或不同的网络层地址,例如2个IP地址,或者1个IP地址、1个OSI地址。

【ARP & RARP】
1. 何时发送ARP请求,何时应答ARP请求?
   当单播发送IP数据并且查询ARP高速缓存失败时,就会广播一个询问目的主机硬件地址的ARP请求;当接收到ARP请求的主机就是该请求所要查找的目的主机或目的主机的ARP代理服务器时,就会单播一个ARP应答。
2. 为什么两者的以太网帧类型不同?
   ARP值为0x0806,RARP为0x8035,其实对于发送方来说,利用ARP的op字段可以区分RARP,但对于接收方,由于ARP实现在内核中,而RARP一般实现为服务器,所以为了更易区分,就单独用另一个值标识。
3. 设计RARP服务器有哪些问题?
   一是怎么发送以太网帧以响应请求,这与系统相关。二是当存在多个服务器时,同时发送响应帧会造成以太网冲突,这可以通过分主从服务器和随机延时来优化避免。
4. ARP在等待应答时,它会如何处理发往给定目的的多个报文?
   在大多数的实现中,在等待一个ARP应答时,只将最后一个报文发给特定目的主机。Host Requirements RFC要求实现中必须防止这种类型的ARP洪泛,建议最高速率是每秒一次。
5. 免费ARP有什么作用?
   一般的ARP请求用于查询目标硬件地址,并等待应答。而免费的ARP发出请求并不一定期望应答,这可以有两方面的作用:
   1)一个主机可以确定是否存在相同IP地址的另一主机
   2)当本机硬件地址改变时,通知其它主机更新ARP高速缓存。
6. ARP如何映射一个IP多播地址?
   先获取IP多播地址的低23位,再与常量0x01005e7f0000按位或,结果就是对应的多播硬件地址。

【IP】
1. 何时何地分片?
   当数据报长度大于链路接口MTU且DF=0时,开始分片,分片可发生在源主机,也可发生在中途路由器。若需要分片但DF=1,则向源主机发送ICMP不可达差错。
2. 如何分片?
   1)计算每个分片的数据长度(不含IP首部),除后一个分片外,其它分片数据长度为8字节的倍数。
   2)除复制对应数据外,还复制原始分组的首部及(部分)选项到新的每个分片中,更新新分片首部的头部长度、总长度、MF标志和偏移量。如果原始分组已经是分片,那么MF=1,否则最后一个分片MF=0,其余MF=1。
3. 何时何地重装?
   由于分片可以有不同的路由,而且中途路由器可能再次分片,因此只有目标主机才能重装所有分片。当接收端第一次收到一个MF或偏移量非零的分组时,则该分组就是一个必须被重装的分片,于是开始重装。
4. 如何重装?
   1)使用4元组{源地址,目标地址,协议,16位标识}为唯一标识查找当前分片所属的数据报(分片表),如果没有找到,则创建分片表,按偏移量将当前分片插入到分片表,并启动重装定时器。
   2)如果重装定时器超时后,还没有组装好一个完整的IP数据报,此时如果已经收到第一个分片,则向源主机返回ICMP超时差错,最后丢弃收到的所有分片;否则,提交数据给适当的传输层处理。
5. 哪些分组能被转发,何时转发?
   到达非最终目的地系统的分组,且当系统配置为可转发或分组包含源路由时,才能被转发,但下列类型的分组除外:1)链路层广播 2)环回分组 3)网络0和E类目标地址 4)D类目标地址。

【ICMP】
1. ICMP报文有哪些类型,何时何地生成这些报文?
   包括请求、应答、差错和重定向4种,其中前两者可统一为查询类。请求当需要查询的时候由进程生成,应答由当内核收到请求报文时生成,当主机发出的数据报无法成功地提交给目的主机时,目的主机或中间路由器的IP或传输协议生成差错报文,并返回给原来的系统。
2. 内核怎么处理收到的ICMP报文?
   ICMP是一种传输层协议,其协议号为1,当IP层收到一个ICMP报文时,分用交给ICMP协议输入处理,ICMP协议输入根据其类型分别处理:1)请求---生成适当的应答报文 2)差错---提交给适当的传输层协议处理 3)应答---提交给等待ICMP报文的进程 4)重定向---更新路由表,并提交给等待的进程。
3. 怎么发送ICMP报文?
   构造ICMP报文-->计算ICMP检验和-->封装到IP数据报中-->提交给IP协议输出处理,对于用户进程,须使用原始IP机制才能发送。
4. 哪些情况不会产生ICMP差错报文,为什么?
   1)ICMP差错报文:违反此条可能导致差错引起差错,无休止循环下去。
   2)源地址不是单播地址的IP数据报:违反此条导致差错可能同时发到多个主机。
   3)目的地址是广播或多播地址的IP数据报:违反此条导致多个主机可能同时响应。
   4)作为链路层广播的数据报:违反此条导致多个主机可能同时响应。
   5)不是IP分片的第一片:违反此条可能导致产生多个ICMP差错,每个分片一个。
   由此可见,违反以上几条都会引起网络风暴。

【TCP & UDP】
1. 为什么TCP首部存在首部长度字段,而UDP却没有?
   TCP首部存在选项,如mss,timestame,nop和wscale等。
2. 为什么这两种协议首部前面都是源和目的端口?
   当TCP收到一个ICMP差错时,必须检查两个端口号以决定差错对应于哪个连接;只有当UDP套接口连接到对端时,用户进程才会收到ICMP差错,例如当服务器未运行时,返回的ICMP端口不可达消息。
3. 当收到TCP或UDP数据包时,怎么提交给应用层?
   插口由进程调用socket或accept创建,关联到对应的PCB(协议控制块)上,通配匹配数由本地和外部IP地址确定,有3种取值:0--本地和外部IP都不为*、1--本地或外部IP有一个为*和2--本地和外部IP都为*。与UDP不同的是,TCP还有自己的PCB。
   1)TCP:先扫描Internet PCB,查找最小通配匹配数的插口,如果没找到,那么响应RST包;再查看对应的TCP PCB,若不存在则响应RST包,否则若TCP 状态为关闭,则丢弃;最后交付给找到的对应插口。
   2)UDP:这里要分2种情况,对于目的地为广播或多播地址的IP数据报,交付给所有匹配的插口;对于目的地为单播的IP数据报,扫描Internet PCB,查找具有最小通配匹配数的插口,如果没有找到,则向源主机发送ICMP端口不可达差错。如果有多个插口有相同的最小通配匹配数,那么具体由哪个插口接收依赖于不同的实现。
4. 计算首部检验和时,为什么要引入伪首部?
   这是因为考虑到IP层的可能差错,TCP和UDP需要验证数据包是否被递送到正确的协议和目的主机。
5. UDP何时会计算检验和,如何区分是否使用了检验和?
   UDP的检验和是可选的,当系统没有禁止(udpcksum非零)时,发送方会计算检验和,接收方还须输入分组检验和非零时才会计算检验和。如果检验和字段非零,那么就使用了,反之没有。
6. 在TCP状态迁移中,哪些状态在什么情况下可直接转到CLOSED状态?
   SYN_SENT在连接定时器超时后,FIN_WAIT_2在FIN_WAIT_2定时器超时后。
7. 为什么TCP需要持续(persist)定时器、FIN_WAIT_2定时器和2MSL定时器?
   1)因为连接对端发送的窗口通告为ACK报文,而ACK是不会确认的,允许TCP继续发送数据的窗口更新可能会丢失,所以需要设定persist定时器,在超时后发送1字节的数据,判定对端接收窗口是否已打开。
   2)因为在正常情况下,当连接主动关闭时,会由FIN_WAIT_1状态进入FIN_WAIT_2状态等待接收对端的FIN报文,但对方可能一直不发送FIN,所以需要FIN_WAIT_2定时器避免连接永远滞留在FIN_WAI_2状态。
   3)因为当连接主动关闭进入TIME_WAIT状态后,将等待2个MSL时间,在这段时间内,TCP可以重发丢失的ACK,丢弃来自新连接替身的迟到的报文段以防止被曲解,所以需要2MSL定时器,超时后关闭连接。
8. 当TCP发送数据,调用ip_output返回ENOBUFS差错时,可能会发生什么情况?
   当提交给网络层因为内存不足发送失败时,数据包被丢弃。如果丢弃的是数据报文,重传定时器超时后数据将被重传;如果丢弃的是纯ACK报文,对端收不到ACK时会重传对应的数据报文;如果丢弃的是RST报文,当对端重传导致发送RST报文的数据报文时,将再次生成RST报文。
9. TCP何时发送ACK报文?
   对于数据、SYN和FIN报文,发送ACK,但对于纯ACK和RST报文,不会发送;另外当遇以下情况时,则立即发送。
   1)200ms延时ACK定时器超时;2)收到失序的报文段;3)三次握手收到了SYN;4)收到了FIN。
10. TCP何时发送RST报文?
   1)当收到报文段,但没有找到对应的internet pcb或tcp pcb。
   2)当连接处于LISTEN状态时,收到了ACK报文段。
   3)当连接处于SYS_SENT状态时,收到了错误的ACK报文段(ack小于等于iss或大于snd_max)。
   4)当连接被动关闭时(状态大于CLOSE_WAIT),收到了数据。
   5)当连接处于SYN_RCVD状态时,收到了错误的ACK报文段(ack小于snd_una或大于snd_max)。
【Domain & Protocol】
1. 什么是域,它和协议有什么关系?
   域可以理解为一种容纳协议的空间,它的存在便于了协议的分类;域和协议是集合与元素的关系,一个域中的每个协议使用同类地址,并且每种地址只被一个域使用,一个域能由协议族或地址族常量唯一标识。
2. TCP/IP中有哪些域及其协议?
   internet、iso、route、ccitt、imp、network systems和unix,其中internet域含有ip,icmp,igmp,tcp和udp五种协议,unix域用于ipc通信。
3. 哪些地方会用到域?
   一个网络层协议必须分用输入数据报,并交给相应的传输层协议,由于域包含了协议族,因此必须从对应的域中找到合适的协议去处理。例如IP对应的域为internet,这个域对应的协议族为inetsw,当收到IP数据报时,就从inetsw中找到对应的传输层协议去输入处理。

【IP Addressing】
1. IP地址有哪几类?
   分为5类,A、B和C类用于单播;D类用于多播;E类用于实验。
2. sockaddr和sockaddr_in有什么区别联系?
   sockaddr是一种通用的用于接口编址信息的结构,它将硬件与协议的地址细节相对于接口层隐藏起来,成员依次为sa_len、sa_family和sa_data,而sockaddr_in成员依次为sin_len、sin_family、sin_port、sin_addr和sin_zero。 它们的前两个成员其实是一样的,只是命名不同,而sockaddr_in中的sin_port标识传输层的端口,sin_addr标识IP层的地址,所以它是Internet协议的专用接口编址结构,sin_zero仅为填充用,因为sockaddr_in长度不应小于sockaddr。
3. 插口编址结构允许的最大长度是多少?
   sockaddr最后一个成员是可扩展的,这是C语言的通用技术,因为其第一个成员为u_char类型,所以最大长度是255。
4. 一个接口可以配置多个IP地址,是怎么实现的?
   ifaddr表示通用的接口地址,ifnet表示接口,它有个类型为ifaddr*的if_addrlist成员,表示当前接口上的地址链表。in_ifaddr表示Internet协议专用的接口地址,而IP属于Internet协议,因此用in_ifaddr表示,所有的IP地址组成一个类型为in_ifaddr*的链表。当增加一个IP地址时,就需要插入这两个链表中;当删除一个IP地址时,就需要从它们当中移除。
5. 为什么配置IP主机地址和网络掩码可以是独立的?
   因为它们使用不同的命令实现,前者用SIOCSIFADDR,后者用SIOCSIFNETMASK。当配置IP主机地址时,如果没有指明网络掩码,那么网络掩码被设置成默认的。
6. 为什么访问IP接口地址使用的是UDP插口而不是原始IP插口?
   只有超级用户用程才能创建原始IP插口,而通过UDP插口,任何用户进程都能查看接口配置。

【Socket】
1. 为什么会存在插口层?
   从概念上讲,tcp/ip协议栈划分为链路、网络、传输和应用4层;但从实现上讲,在应用层和其下层中间,引入了一个插口层,作为进程和内核通信的桥梁,主要功能是将进程发送的与协议有关的请求映射到产生插口时指定的与协议有关的实现,从而屏蔽了不同协议处理的细节。
2. 为什么服务器进程总是要调用bind,客户进程能调用它吗?
   bind将一个本地地址同一个插口相关联,客户进程需要同一个已知地址建立连接或发送数据报到已知地址,如果不调用bind,服务器进程就无法在某个已知地址上接受TCP连接或接收UDP数据报。客户进程也能调用bind,这样便可以由应用程序而非内核来选择一个本地地址,其结果是只能接收目的地址为被绑定地址的数据包,但通常不必调用bind,因为内核会自动决定外出地址和临时端口。
3. 对于tcp和udp协议的插口,调用connect有什么区别联系?
   共同点是设定插口的外部地址(插口的地址存储在相关的协议控制块中),不同点如下
   1)tcp:与远端系统进行3次握手交互,如果插口是非阻塞的且连接正在进行中,那么返回EINPROGRESS,下次再调用则返回EALREADY;如果连接成功,无论是否阻塞,那么下次再调用会返回EISCONN;如果连接失败,那么下次再调用,则重新开始三次握手。
   2)udp:没有3次握手交互,直接设定外部地址,无论插口是否阻塞,调用会立即返回,多次调用则会替换老的外部地址。发送数据必须使用write或目的地址为空的sendto,若sendto目的地址非空,则返回EISCONN。如果没有事先调用connect,那么调用目的地址为空的sendto则会返回ENOTCONN。
4. 什么情况下调用close会阻塞?
   连接已建立且设置了SO_LINGER选项并延时值非零的阻塞插口。
5. 插口IO有哪些系统调用?
   发送有write、writev、sendto和sendmsg,接收有read、readv、recvfrom和recvmsg。注意,send和recv是库函数而非系统调用,前者调用sendto实现,后者调用recvfrom实现。
6. write、writev、read、readv与sendto、sendmsg、recvfrom、recvmsg有什么不同?
   1)前面4个适合于任何描述符,而后面4个只能用于插口。
   2)前面4个不支持标志,而后面4个支持。
   3)前面前2个不支持目的地址、后2个不支持源地址,而后面前2个支持目的地址、后2个支持源地址。
   4)前面4个不支持控制信息,而后面第2个和第4个支持。
7. 如何断开已连接的udp插口,允许调用sendto向其它主机发送数据?
    由于系统并没有提供形如disconnect的断连API,但connect内部实现是先断连,再调用对应协议的PRU_CONNECT请求处理,因此向connect传递无效的外部地址结构(如IP=0.0.0.0,Port=0),虽然这样会导致结果失败,但先前的断连成功,对应pcb的外部地址被设为INADDR_ANY,所以调用sendto就不会返回EISCONN。

【Raw IP】
1. 怎么使用原始IP,它有哪些用途及应用?
   创建SOCK_RAW类型的原始插口,就能使用原始IP机制,它有下列用途:
   1)发送和接收ICMP和IGMP报文,如ping程序和多播路由守护程序。
   2)构造自己的IP首部,如路由跟踪程序。
   3)设计基于IP的新的传输层协议,如gated程序。
2. 协议值为PROTOCOL_RAW(255)的原始插口能收到什么类型的IP数据报?
   由于255是非零的保留值,这样的IP数据报在网络中不会存在,原始IP输入处理协议比较测试失败,因此收不到任何类型的IP数据报。
3. 协议值为0的原始插口能收到什么类型的IP数据报?
   由于协议值为0,原始IP输入处理忽略了协议比较测试,因此能收到任何类型的IP数据报。
4. 如何处理收到的IP数据报?
   遍历Internet PCB表,依次从协议值、本地地址和外部地址三项来比较IP数据报和每个PCB,将IP数据报复制追加到所有匹配的PCB对应的插口缓存中,并唤醒等待的进程。
5. 如何发送数据?
   先填充IP首部,如果未设置IP_HDRINCL选项,那么由内核填充,否则由应用程序在发送前填充,再交给IP协议输出处理。
6. 内核何时会调用原始输入?
   当收到的协议类型为除IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP和IPPROTO_IGMP外的IP数据报时调用。

【Unix domain】
1. 使用unix域的原因有哪些?
   1)当通信双方在同一主机上时,使用unix域插口的速度比tcp和udp插口要快很多。
   2)支持同一主机进程间传递描述符。
2. unix域和internet域有什么不同?
   1)编址结构不同:前者是sockaddr_un,与文件系统路径名关联,而后者是sockaddr_in,与IP地址和端口关联。
   2)协议控制块不同:前者是unpcb,没有全局的pcb链表,而后者是inpcb,有全局的pcb双向循环链表。
3. 如果一个unix域服务器在bind后unlink了被绑定的路径名,会发生什么情况?
   因为connect内部实现查找路径名失败,所以连接失败,但listen会成功,因为bind会创建新的vnode和pcb关联,且PRU_LISTEN请求实现只检查vnode是否为空。
4. 如果一个unix域服务器在终止时没有unlink被绑定的路径名,会发生什么情况?
   因为connect内部实现虽能找到路径名但找不到相关的插口,所以连接被拒绝。
5. 系统调用socketpair和pipe有什么区别联系?
   共同点是使用unix域,即socket调用第1参数为AF_UNIX,不同点如下
   1)前者是双工的,因为两个插口标志都为读写,且它们的pcb相互指向对方;后者是单工的,因为一个插口标志为只读,另一个为只写,写插口的pcb指向读插口的pcb。
   2)前者支持数据报和流式插口,后者仅支持流式插口。
6. unix域是怎么实现传递描述符的?
   描述符存储在控制信息cmsghdr内,cms_level=SOL_SOCKET且cms_type=SCM_RIGHTS,unix域的发送请求实现将描述符转换为file指针,这个过程叫内部化,接收请求实现把file指针转换为最小的没有使用的描述符,这个过程叫外部化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值