TCP/IP详解 卷I 笔记

第1章 概述


知识点比较少,主要一个是不同的网络层:应用层  传输层  网络层 链路层
它们分别对应的协议,比如IP协议对应网络层 TCP协议对应传输层 以太网协议对应链路层。
另外一个是IP地址分类:
A类0开始,网络号占一个字节
B类10网络号占两个字节
C类110网路号占三个字节
D类1110,剩余的是28位多播地址
E类11110,剩余的位留待后用
另外一个需要稍微留意一下的问题是端口号问题。

第2章 链路层


链路层主要有三个目1为IP模块发送和接收IP数据报;2.为ARP模块发送ARP请求和接收ARP应答;3.为RARP发送和接收RARP请求和应答。

链路层封装的主要目的是进行帧定界,必须使得接收方可以正确的读出相应的帧。至于校验过程和封装以及往返时间的具体过程我们不再关注。注意这里有一个最大传输单元MTU的概念。以太网和802.3对数据帧的长度都有一个限制,其最大值分别是1500和1492字节。如果IP层有一个数据报要传,但是它的长度比链路层的MTU还大,那么IP层就需要进行分片。
路径MTU:具体的路径MTU发现方法后面后介绍。这里还涉及到ICMP和IP分片方法。
我们现在就具体看一下IP和ICMP的分片方法,首先我们来分析一下要把一个数据报分片需要注意什么。我们必须保证分片后接收到数据报还能恢复成原来的样子,另外假如我们收到一个分片还需要知道它是属于那个数据报的。所以这里需要几个标志。如下图


需要注意的,在分片的数据中,传输层的首部只会出现在第一个分片中。因为传输层的数据格式对IP层是透明的,传输层的首部只有在传输层才会有它的作用,IP层不知道也不需要保证在每个分片中都有传输层首部。所以,在网络上传输的数据包是有可能没有传输层首部的。

避免IP分片

在网络编程中,我们要避免出现IP分片,那么为什么要避免呢?原因是IP层是没有超时重传机制的,如果IP层对一个数据包进行了分片,只要有一个分片丢失了,只能依赖于传输层进行重传,结果是所有的分片都要重传一遍,这个代价有点大。由此可见,IP分片会大大降低传输层传送数据的成功率,所以我们要避免IP分片

对于UDP包,我们需要在应用层去限制每个包的大小,一般不要超过1472字节,即以太网MTU1500)—UDP首部(8)—IP首部(20)。

对于TCP数据,应用层就不需要考虑这个问题了,因为传输层已经帮我们做了。在建立连接的三次握手的过程中,连接双方会相互通告MSSMaximum Segment Size,最大报文段长度),MSS一般是MTUIP首部(20)—TCP首部(20),每次发送的TCP数据都不会超过双方MSS的最小值,所以就保证了IP数据报不会超过MTU,避免了IP分片。


第3章 IP:网际协议



IP提供的是无连接的不可靠的服务。IP首部有20个字节。
这些字节包括了版本,首部长度,服务类型,16位总长度,16位标志(区分不同数据报),3位标志(表明是否还有分组),生存周期,8位协议,16位首部检验和。32为源IP地址,32位IP目的地址。
IP路由选择
根据路由表进行转发,转发规则:
搜索路由表,如果有完全匹配的则直接转发。否则
搜索路由,寻找与目的主机网络号相匹配的表目(涉及到子网掩码);否则
寻找默认路由。
如果上面都没成功,那么数据不能发送,如果数据来自本机,那么向生成数据报的应用程序发送一个“主机不可达”或“网络不可达”的错误。如果发送给了默认路由,但是在之后某一个位置处,找不到目标地址,那么同样发送一个ICMP差错报文
上面还要注意,IP报发送过程中目的地址始终没有改变,而每个数据链路层可能具有不同的数据帧首部,而且链路层目的地址始终指向下一站链路层地址,以太网地址一般通过ARP获得。

子网掩码
采用子网掩码后IP地址分为网络号子网号主机号
子网对外部是透明的,对内部则不是透明的。
使用子网掩码的好处:缩减路由表的规模。
我们来看一下习题:
3.1.环回地址必须是127.0.0.1吗?不是
3.3子网号为16bit的A类地址与子网号为8bit的B类地址的子网掩码有什么区别?没有区别
3.5子网掩码255.255.0.255是否对A类地址有效?合法,只是子网不连续的子网掩码,但是RFC不建议这种方式
3.6找出数据报网络层提供的3个优点。
第一:数据报降低了路由器中对连接状态的需求;
第二:数据报提供了基本的构件,在它上面可以构造不可靠的和可靠的运输层;
第三:数据报代表了最小的网络层假定,使得可以使用很大范围的数据链路层服务。

第4章 ARP:地址解析协议


内核(如以太网驱动程序)必须知道目的端的硬件地址才能发送数据。ARP的功能是在32bit的IP地址和采用不同网络技术的硬件地址之间提供动态映射。
点对点链路不使用ARP。
ARP高速缓存
ARP分组格式
对不存在的主机的ARP请求
ARP缓存超时设置
ARP代理
免费ARP
通常发生在系统引导期间进行接口配置的时候。免费ARP有两个方面的作用:
1)一个主机可以通过它来确定另一个主机是否设置了相同的IP地址。
2)如果发送免费ARP的主机正好改变了硬件地址(很可能是主机关机了,并换了一块接口卡,然后重新启动),那么这个分组就可以使其他主机高速缓存中旧的硬件地址进行相应的更新。
一台主机在应答ARP的时候,所有其他主机收到后都会更新?注意ARP应答不是广播的,而是直接发送给ARP请求端的那么还有一个问题,ARP请求广播出去的时候,所有收到的主机都会更新?如果不会,那么上面免费ARP的作用2怎么理解;如果会,不是很容易被攻击吗。
既然每台主机都可以发送ARP请求并在请求中指明自己的硬件地址和IP地址,那么它就可以撒谎。
习题
4.4 试图与更换以太网卡而处于关机状态的服务器连接会发生什么情况?如果服务器在引导过程中广播一条免费ARP,这种情况是否会发生改变。
假如事前我们主机已经在高速缓存中保存了服务器的物理地址,那么由于服务器更换网卡,我们现在将无法与其建立联系,除非等到ARP失效。如果它发送了免费ARP,那么收到该ARP广播的主机会检查缓存,发现相应的硬件地址对应的IP地址已经变化,就更新自己的条目,这样更换网卡后也可以很快就实现通信了。

通过这里我们也发现整个网络协议之间的关系,其实最底层的还是需要像ARP这样的链路层协议。应用层协议好比组装部,运输层协议就好比指挥部,IP层协议就好比地图,链路层协议就好比车辆和道路。

补充
ARP表更新必须同时满足下面两个条件:
1.设备收到来自某Ip的包或者免费ARP
2.设备的缓存表中有与之对应的IP条目。



第5章 RARP:逆地址解析协议



第6章 ICMP:Internet控制报文协议


它通常被IP层或更高层(TCP UDP)使用,ICMP是在IP数据报中被传输的。
ICMP报文的格式和类型我们暂时不予考虑。
ICMP地址掩码请求与应答
ICMP时间戳请求与应答
ICMP端口不可达差错


第7章 Ping程序


Ping程序是为了测试另一台主机是否可达。该程序发送一份ICMP回显请求报文给主机,并等待返回ICMP回显应答。

第8章 Traceroute程序




第9章 IP选路


前面已经说过选路过程:
1)搜索匹配的主机地址;
2)搜索匹配的网络地址;
3)搜索默认表项
需要注意的几点:
每个接口都有一个对应的子网掩码,因此每个路由表都有一个隐含的子网掩码。
主机根本没有与任何网络相连的情况下,TCP/IP协议仍然能够用于这样的主机,但是只能与自己本身通讯,这时的路由表质保含环回接口一项。


第10章 动态选路协议


当相邻路由器之间进行通信,以告知对方每个路由器当前所连接的网络,这时就出现了动态选路。
每个自治系统可以选择自治系统中各个路由器之间的选路协议。这种协议我们称之为内部网关协议IGP或域内选路协议,最常用的IGP就是选路信息协议RIP。一种新的IGP是开放最短路径优先OSPF协议。
外部网关协议 EGP用于不同自治系统之间的路由器。
RIP的运作与单源最短路径算法是相似的

OSPF:开放最短路径优先
与采用距离向量的RIP协议不同的是,OSPF是一个链路状态协议。
它采用的是每个路由器主动的测试与其临站相连链路的状态,将这些信息发送给它的其他临站,而临站将这些信息在自治系统中传播出去。
OSPF与RIP不同在于,它直接使用IP。也就是不使用UDP或TCP。
OSPF采用多播方式,而不是广播方式,以减少不参与OSPF的系统负载。

BGP:边界网关协议
不同自治系统之间的路由器之间进行通信的外部网关协议。

CIDR:无类型域间选路
“无类型”的意思是现在的选路决策是基于整个32bit IP地址的掩码操作,而不管其IP地址是哪类。
CIDR的基本观点是采用一种分配多个IP的方式,使其能够将路由表中的许多表项总和成更少的数目。



第11章 UDP:用户数据报协议


UDP不提供可靠服务,它的头部只有8字节,包括源端口,目的端口,这显然是通信必须的。然后还包括UDP长度字节,和检验和字段。
可见这里的头部非常简单,那么它可以胜任它的任务吗?其实是可以的,比如它可能会发生被分片的问题,这时IP层可以保证在接收端重新组合成新的数据报。
可见UDP是非常自由的,仅仅包含了必要的字段。
UDP检验和
UDP检验和覆盖UDP首部和UDP数据。IP首部的检验和只覆盖了IP的首部UDP的检验和是可选的而TCP的检验和是必须的
如果发送端没有计算检验和而接收端检测到检验和有差错,那么UDP数据报就要被悄悄的丢弃,不产生任何差错报文(IP层检测到IP首部检验和有差错时也是这么做的)。
UDP的检验和是端到端的,它由发送端计算,然后由接收端验证。
尽管UDP检验和是可选的,但是它们应该总是在使用。

IP分片
分片可以发生在发送端主机上也可以发生在中间路由器上。重新组装由目的端的IP层来完成,其目的是使分片和组装过程对运输层是透明的。
需要重申的是任何运输层的首部只能出现在第1片数据中。
ICMP不可达差错
用Traceroute确定路径MTU
采用UDP的路径MTU发现
UDP和ARP之间的交互作用
最大UDP数据报长度
数据报截断
     由于IP能够发送或接收特定长度的数据报并不意味着接收应用程序可以读取该长度的数据。因此UDP编程接口允许应用程序指定每次返回的最大字节数。如果接收到的数据报长度大于应用程序所能处理的长度,那么会发生什么呢?
      不幸的是,这取决于编程接口的实现。
     典型的Berkeley版socketAPI对数据报进行截断,并丢弃任何多余的数据。应用程序何时知道,则与版本有关(4.3BSD Reno及其后的版本可以通知应用程序数据报被截断)
     SVR4下的socket API并不截断数据报。超出部分可以在后面的读取中返回。它也不通知应用程序从单个UDP数据报中多次进行读取操作。
ICMP源站抑制差错
UDP服务器的设计
客户IP地址及端口号
目的IP地址
IP数据报中包含了IP地址,UDP数据报中包含了端口号。当一个应用程序接收到UDP数据报时,操作系统必须告诉它是谁发送了这份消息。

目的IP地址
这要求操作系统从接收的UDP数据报中将目的IP地址交给应用程序。不幸的是并非所有的实现都提供这个功能。

UDP输入队列
通常程序所使用的每个UDP端口都与一个有限大小的输入队列相联系。这意味着,来自不同客户的差不多同时到达的请求将由UDP自动排队。然而,排队溢出造成内核中UDP模块丢弃数据报的可能性是存在的。

===============================================================================
1. 这里的排队是在内核中还是应用空间中
在内核空间根据端口号和协议来决定保存的位置
==============================================================================

限制本地IP地址
大多数UDP服务器在创建UDP端点时都使其本地IP地址具有通配符的特点。这就表明进入的UDP数据报如果其目的地为服务器端口,那么任何本地接口均可接收到它。

限制远端IP地址
大多数系统允许UDP端点对远端地址进行限制,也就是只能接收特定IP地址和端口的UDP数据报

每个端口有多个接收者
尽管在RFC中没有指明,但是大多数系统在某一时刻只允许一个程序端点与某个本地地址及UDP端口号相关联。当目的地为该IP地址及端口号的UDP数据报到达主机时,就复制一份传给该端点。端点的IP地址可以含星号,正如我们前面讨论的那样。
在一个支持多播的系统上,多个端点可以使用同一个IP地址和UDP端口。
当UDP数据报到达目的IP地址为广播地址或多播地址,而且在目的IP地址和端口号处有多个端点时,就向每个端点传送一份数据报的复制。但是,如果UDP数据报到达的是一个单播地址,则只向其中一个端点传送一份数据报的复制,选择哪个端点传送基于各个不同的系统实现。

习题
2.阅读RFC,理解为什么除最后一片外,其他片中的数据长度均要求为8字节的整数倍?
3.假定有一个以太网和一份8192字节的UDP数据报,那么需要分成多少个数据片,每个数据报片的偏移和长度为多少?
对IP来说有8200字节要发送,8192字节的用户数据和8个字节的UDP首部。采用tcpdump记号,第一个分片是1480@0+(1480字节的数据,偏移为0,将更多片比特置1),第二个是1480@1480+第三个是1480@4440+,第4个是1480@4440,第5个是1480@5920+,第6个是80@7400,1480*5+800=8200,正好是要发送的字节。
4.继续前一题,假定这些数据报片要经过一条MTU为552的SLIP链路。必须记住每一个数据报片中的数据(除IP首部外)为8字节的整数倍,那么又将分成多少个数据报片?
每个1480字节的数据报片被分成三小片:两个528字节和一个424字节。小于532(552-20)的8的最大倍数是528。800字节数据报片被分成两小片:一个528字节和一个272字节。
5.一个用UDP发送数据报的应用程序,它把数据报分成4个数据报片。假定第1片和第2片到达目的端,而第3片和第4片丢失了。应用程序在10秒后超时重发该UDP数据报,并被分为相同的4片。假定这一次接收主机重新组装的时间为60秒,那么当重发的第3片和第4片到达目的端时,原先收到的第1片和第2片还没有被丢弃。接收端能否把这4片数据重新组装成一份IP数据报?
不能。重传时数据报有一个新的标志字段。而重新装配只针对那些具有相同标志的分段。
9.在图1-8中,我们说UDP数据报是根据目的UDP端口号进行分配的。这正确吗?
不,在11.12节我们看到许多实现可以根据目的IP地址,源IP地址和源端口号来过滤送往一个给定UDP端口号的输入数据报。

第12章 广播和多播


第13章 IGMP: Internet组管理协议


第14章 DNS:域名系统


第16章 BOOTP:引导程序协议


第17章  TCP: 传输控制协议


面向连接的/可靠的字节流服务。
在一个TCP连接中,仅有两方进行彼此通信。在第12章介绍的广播和多播不能用于TCP。
TCP通过以下方式来提供可靠性:
1.应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度保持不变。
2.当TCP发出一个段后,它启动一个计时器,等待目的端确认接收到这个段。如果不能及时收到一个确认,将重发这个段。
3.TCP将保持它的首部和数据检验和。目的是检测数据在传输过程中是否发生变化,如果检验和有差错,丢弃不予处理,等待对方超时重传。
4. 将收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
5.既然IP数据报会发生重复,TCP的接收端必须丢弃重复数据。
6.TCP还能提供流量控制。

17.2TCP的首部


还有一个问题,因为数据可能会被分片,这是在IP层进行的,那么对于UDP来说,IP层需要把分片信息也传给UDP层?
对于TCP它可以根据窗口进行发送,所以不会发生分片
现在我们可以回答这个问题了,首先第一个问题,IP层会将分片组装后交给传输层,如果还有分片超时未到,就会把整个丢弃,不给上层交付,这样会由上层来决定是否重传。
第二个问题,我们知道TCP的最大发送大小不会超过MSS,但是中间路由器会不会对IP数据报分片呢

第18章 TCP连接的建立和终止


建立连接协议
1.请求端发送一个SYN段指明客户打算连接的服务器端口,以及初始序号(ISN)。
2.服务器发回包含服务器初始序号的SYN报文段作为应答。同时将确认序号设置为客户端序号ISN+1以对客户端的SYN报文进行确认。一个SYN将占用一个序号。
3.客户端必须将确认序号设置为服务器的ISN加1,以对服务器的SYN报文段进行确认。
其实这里还有几个问题,由于网络环境的原因,每一步我们都无法保证报文段一定能到达对方,那么如果第一个阶段报文段丢失会发生什么?是不是等待超时后重发?如果重发,那么此时的序号怎么设置?
第二,如果第二步,也就是服务端发回的确认段丢失怎么办?这时客户端的情况同上面是一样的,对于服务端,它收不到客户端的确认又会怎样?继续回复吗?如果继续回复那么它的序号怎么设置?
第三,如果第三步的报文段丢失怎么办?

我们再来看一下每一步发送之后客户端和服务端所处的状态名字。
第一步客户端发出之后,处于同步已发送状态(SYN_SEND);
第二步,服务端收到报文后,发送确认后,处于同步已接收状态(SYN_RECV);
第三步,客户端接收到报文后,处于连接建立状态(ESTABLISHED)。
服务端接收客户端的确认之后,也处于连接建立状态(ESTABLISHED)。

ISN随着时间而变化,每4ms加1,。这样选择的目的在于防止在网络中被延迟的分组在以后又被传送,而导致,某个连接的一方对它作错误的解释。

2.如果一个客户端与服务端建立了TCP连接,那么其他的客户端就不能在此端口上再与其建立连接了?必须要等到该连接完成才能处理另外的连接?那效率岂不是无法保证?在编程中,我们通常开一个线程来处理不同的连接,那么这时是怎么处理的
这个问题,我们在下面已经回答了,注意socket是四元组就可以理解了。
3. 区分不同TCP连接靠的是什么?我的意思是如果当前的TCP连接正在连接过程中。这时其他客户端发送了一个报文段,要与该服务器的该端口建立TCP连接,那么我怎么知道这个请求不是已经连接的客户端发送过来的?通过源IP和源端口来判断,还是通过其标志位比如序号来区分的?是否是这样,一旦建立其连接后,TCP就会把接收到的数据放到一个缓冲区中,这些报文可能并不会按顺序到达,TCP会根据它们的序号将它们放到指定的位置,并且超过一定时间还未到达的就会被要求重传,直到所有数据组成按顺序的序列,才能交给应用程序。根据上面这段描述,正常情况下因为服务端该端口已经建立连接,其他客户端不会发送数据到该服务器该端口,这时比较好处理。但是如果其他一个客户端伪造报文段发送过来,怎么办?如果伪造的源IP+源端口与已经建立连接的客户端不一致怎么样?如果一样又会怎么样

4. IP层是不会要求进行重传的,但是它必须对分片进行组装,以使得对传输层透明。
那么如果IP层有一个分片迟迟不到,那么它会一直等待吗?那么他是在一段时间后直接丢弃还是把不完整的数据交给 传输层
来自网络的答案:
mtu层的分片和重组是IP层的事情,如果丢了一片,IP层就会丢弃全部。这样在udp层一个分片都收不到,就需要应用层重传。
==============================================================================
我们知道TCP发送的数据到达的顺序可能会不一样,那么内核是怎么维护这个缓冲区的呢?
这一点可以从《计算机网络》谢希仁版上找到答案。我们下面简单总结下这个问题。
这里涉及到应用程序与TCP缓冲区的交互。要更好的理解这个过程一定要明白发送缓冲区和接收缓冲区是作为环状数组来使用的,这样才能正确计算窗口大小。另外要注意接收端收到连续的内容后会给发送段发送确认号,确认号的下一个位置就表示接收端希望下一次接收到的数据,但是发送端并不一定要在收到确认后,发送下一个数据,因为下一个数据可能已经发送过了,这里是靠计时器来控制是否需要重新发送的。
接下来我们看一下应用程序与TCP缓冲区的关系。
5. 我们知道如果应用程序不能及时读取缓冲区中的数据,那么可能导致接收窗口变为0,从而阻止发送端数据的发送。现在我们来考虑一下,怎么才能让接收端及时读取TCP缓冲区中的数据呢?我们在c程序中的read函数最终会调用TCP协议的read函数,在没有数据的时候,我们的c函数会阻塞,那么当内核缓冲区中接收到数据之后呢?会立刻给应用程序吗?二者之间又是怎么协作呢
6. 我们在介绍上面的接收缓冲区,发送缓冲区的时候,提到了未按序到达的数据问题,那么还是之前提到的问题,我们怎么确定把未按序到达的数据放到缓冲区的哪个位置的

第6个问题我们现在可以解决了,注意TCP首部有偏移地址,根据这个偏移地址,我们就知道该放在缓冲区何处了。另外注意缓冲区是循环使用的。
其实源码中并没有采用数组的形式。

解决序号回绕问题的源码
  1. /*
  2. * The next routines deal with comparing 32 bit unsigned ints
  3. * and worry about wraparound (automatic with unsigned arithmetic).
  4. */

  5. static inline int before(__u32 seq1, __u32 seq2)
  6. {
  7. return (__s32)(seq1-seq2) < 0;
  8. }
  9. #define after(seq2, seq1) before(seq1, seq2)
7.每个TCP连接都有自己的接收缓冲区与发送缓冲区?
这个是对
18.5 TCP的半关闭

TCP提供了连接的一端在结束它的发送之后还能接收来自另一端数据的能力。这就是所谓的半关闭。
下面我们回忆一下TCP的关闭过程:
1.客户端给服务端发送FIN报文段,序号为M,发送完成后进入FIN_WAIT1状态。
2.服务端收到客户端关闭报文后回复一个ACK报文,序号为M+1,进入CLOSE_WAIT状态。
3.客户端接收到服务端的ACK报文后,进入FIN_WAIT2状态。这时客户端还不能关闭,因为还有可能收到来自服务端的数据。
4.服务端不再发送数据给客户端了,这时它给客户端发送一个FIN报文段,序号为N,然后进入LAST_ACK状态。
5.客户端收到服务端的FIN报文知道服务端已经没有数据发送了,这时双方的连接过程基本结束了,客户端给服务端回复一个确认报文,序号N+1,客户端进入TIME_WAIT状态,客户端这时还不能立刻关闭,注意这里不立刻关闭并不是因为担心服务端会收不到客户端的确认报文,毕竟在TCP连接的建立过程中我们也面临同样的问题,但是我们并没有等待。其实这里的等待是因为我们担心之前滞留在网络中的数据可能会在我们关闭后重新到达,导致下一次连接误解这些数据
更正上面说的一点错误:等待2MSL,可以让TCP再次发送最后的ACK以防止这个ACK丢失(服务端超时重发最后的FIN)
8. 如果重发的FIN丢失了,或者客户端收到重发的FIN再次确认时还会重新等待2MSL吗?
9 .这里的误解是不是只有同一客户端同一端口再次与同一服务端的同一接口再次建立连接时才会出现?
是的。
6.服务端收到确认后,进入CLOSED状态。
这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口不能再次被使用。在连接处于2MSL等待时,任何迟到的报文都被丢弃。
如果我们终止一个已经建立连接的服务器程序,并试图重新启动这个服务器程序,服务器将不能把它的这个熟知端口赋值给它的端点,因为它处于2MSL连接的一部分。在重新启动服务程序前,它需要1~4分钟。

FIN_WAIT_2状态
在FIN_WAIT_2状态我们已经发出了FIN,并且另一端也已经确认。只有当另一端的进程完成这个关闭,我们这端才会从FIN_WAIT_2状态进入TIME_WAIT.这意味着我们可能永远保持这个状态。另一端也将处于CLOSE_WAIT状态,并一直保持这个状态直到应用层决定进行关闭。

复位报文段
到不存在的端口的连接请求
无论何时一个报文段发往基准的连接(由插口指明的连接)出现错误,TCP都会发出一个复位报文段。对于UDP,当一个数据报达到目的端口时,该端口没在使用,那么它将产生一个ICMP不可达的信息。而TCP则使用复位。
异常终止一个连接
有时可能发送一个复位报文段而不是FIN来中途释放一个连接。有时称这为异常释放。
异常终止对于应用程序来说有两个优点:(1)丢弃任何待发数据并立即发送复位报文段;(2)RST的接收方会区分另一端是异常关闭还是正常关闭。应用程序使用的API必须提供产生异常关闭而不是正常关闭的手段。
检测半打开连接
如果一方已经关闭或异常终止连接而另一方却还不知道,这种TCP连接称为半打开的。
这时我们假设服务器重新启动,那么客户端发送请求过来,我们发现这个请求的端口还未使用,就会给他发回一个复位报文段,这时客户端收到后就终止连接;那么假如服务器重新启动后又重新在同一个端口上建立侦听呢?
10.这时应该是不可以的,我们估计每个新建立的服务端socket,都会关联客户端socket,发送过来的报文会检查是否是已经建立连接的某个socket的,如果不是直接丢弃或给其发送复位报文段

同时打开
这需要每一方使用一个对方熟知的端口作为本地端口。这又称为同时打开。

同时关闭
当应用程序发出关闭命令时,两端都从ESTABLISH状态变为FIN_WAIT_1, 两端接收到FIN报文后都从FIN_WAIT_1状态变为CLOSING状态,并发送确认ACK。两端收到ACK之后,状态变为TIME_WAIT。
可见中间少了FIN_WAIT_2状态。这是TCP协议单独考虑的情况。
TCP选项
TCP服务器的设计

TCP服务器端口号
这里要注意一个服务器不一定只有一个IP地址,有几个网络接口就会分配几个IP地址。
TCP仅通过目的端口号无法确定哪个进程接收到了一个连接请求。另外,在三个使用端口23的进程中,只有处于Listen的进程能够接收到新的连接请求。处于ESTABLISHED的进程将不能接收SYN报文段,而处于LISTEN的进程将不能接收数据报文段。

限定本地IP地址
为服务器指明一个IP地址,这样只有到达这个IP地址的请求才会被处理
限定远端IP地址

呼入连接请求队列
可能出现当服务器正在创建一个新的进程时,或者操作系统正忙于处理更高优先级的进程时,到达多个连接请求。
在伯克利的TCP实现中采用以下规则:
1)正在等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已经被TCP接受(即三次握手已经完成)但是还没被应用层接受。(应用层还不知道建立了连接?)
2)应用层将指明该队列的最大长度,这个值通常称为积压值。
3)当一个连接请求到达时,TCP判断该请求是否能够被处理。
4)如果对于新的连接请求,该TCP监听的端点的连接队列中还有空间,TCP模块将确认SYN并完成连接建立。另外,当客户进程的主动打开成功但服务器的应用层还不知道这个新的连接时,它可能会认为服务器进程已经准备好接收数据了(如果发生这种情况,服务器的TCP仅将接收的数据放入缓冲队列)。
5)如果对于新的连接请求,连接队列中已经没有空间,TCP将不理会收到的SYN。
当队列已满时,TCP将不理会传入的SYN,也不发回RST作为应答啊。因为如果发回RST,客户进程的主动打开将被废弃,而这个条件可能在一个很短的时间内改变。

11. 内核接收到网络数据之后,是一直传送到传输层
12.接上一个问题,如果是一个连接请求,传输到传输层后,是直接建立连接还是怎么,这是在中断下半步完成的

第19章 TCP的交互数据流


Nagle算法

第20章 TCP的成块数据流


在15章我们看到TFTP使用了停止等待协议。数据发送方在发送下一个数据块之前需要等待接收方对已发送的数据进行确认。本章,我们介绍TCP所使用的被成为滑动窗口协议的另一种形式的流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组(累积确认)。这样可以加快数据传输。
以下内容是介绍滑动窗口的,对此我们已经比较熟悉了,不再多写。
ans:这里明白了前面一个疑惑,就是关于接收数据在缓冲区中如何存放的问题,我们知道TCP首部中有偏移字段,我们可以据此决定数据的存放位置。确认的时候,我们会对连续收到的数据的末端进行确认,同时会通知发送方现在的窗口

PUSH标志
通过允许客户应用程序通知其TCP设置PUSH标志,客户进程通知TCP在向服务器发送一个报文段时不要因等待额外数据而使已提交数据滞留在缓存中。类似的,当服务器的TCP接收到一个设置了PUSH标志的报文段时,它需要立即将这些数据递交给服务器进程。
目前大多数API不提供通知其TCP设置PUSH标志的方法。许多实现认为PUSH标志已经过时,一个好的TCP实现赢能够自行决定何时设置这个标志。

慢启动
这是针对窗口控制的不足设计的。我们知道,接收端会给发送端一个窗口大小,然后发送端就会根据这个窗口进行发送,这在网络环境足够好的情况下是可以的。比如局域网内是可以的,但是在比较复杂的网络环境中,就存在漏洞。当发送方和接收方之间存在多个路由器和较慢速率的链路时,就可能会出现一些问题。一些中间路由器必须缓存分组,并有可能耗尽存储器空间。
现在,慢启动算法根据观察新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作。
这里注意拥塞窗口(cwind)和通告窗口的区别。前者是用于发送方使用的流量控制,后者是用于接收方使用的流量控制。接收方每接收一个ACK就把拥塞窗口增加一个报文段。发送方取拥塞窗口和发送窗口的最小值。

13拥塞窗口cwnd在首部中有对应的结构?否则是放在哪里的?

14.前面我们多次提到输入缓冲区,输出缓冲区。那么内核网络模块接收到TCP数据后是如何把它保存到相应的地方的?对应的数据结构是什么
成块数据的吞吐量
这里的拥塞情况可以想象大量水流通过细管的情景。
紧急方式

第21章 TCP的超时与重传


对每个连接,TCP管理4个不同的定时器。
1)重传定时器使用于当希望收到另一端的确认。本章讨论这个问题。
2)坚持定时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。第22章将讨论这个问题。
3)保活定时器可以检测到一个空闲连接的另一端何时崩溃或重启。第23章讨论。
4) 2MSL定时器测量一个连接处于TIME_WAIT状态的时间。

超时与重传的简单例子
。。。。。。。
在本章的后面,我们将看到当第一次发送后所设置的超时时间实际上为1.5秒,此后该时间在每次重传时增加1倍并直至64秒。
这个倍乘关系被成为“指数退避”。

 往返时间测量
由于路由和网络环境的变化,这个时间可能会经常发生改变。TCP应该跟踪这些变化,并相应的改变其超时时间。
具体内容不再详细分析

拥塞避免算法
拥塞避免是一种处理丢失分组的方法。拥塞避免和慢启动是两个目的不同,独立的算法。但是当拥塞发生时,我们希望降低分组进入网络的传输速率,于是可以调用慢启动来做到这一点。
拥塞避免算法和慢启动算法均需要对每个连接维护两个变量:一个拥塞窗口cwnd和一个慢启动门限ssthresh。这样得到的算法的工作过程如下:
1)对一个给定的连接,初始化cwnd为1个报文段,ssthresh为65535个字节。
2)TCP输出例程的输出不能超过cwnd和对方通知窗口。
3)当拥塞发生时(超时或收到重复确认),ssthresh被设置为当前窗口大小的一半(cwnd和接收方通告窗口大小的最小值,但最少为2个报文段)。此外,如果是超时引起了阻塞,则cwnd被设置为1个报文段。
4)当新的数据被对方确认后,就增加cwnd,但增加的方法依赖于我们是否正在进行慢启动或拥塞避免。如果cwnd小于或等于ssthresh,则在进行慢启动,否则我们正在进行拥塞避免。慢启动一直持续到我们回到当拥塞发生时所处的位置一半的时候才停止(因为我们记录了在步骤2中给我们制造麻烦的窗口大小的一半),然后转为执行拥塞避免。
这里需要体会一下这里面的思想,当拥塞发生时,我们把阈值设为当前窗口的一半,cwnd为1个报文段,然后开始执行慢启动过程,虽然名字叫慢启动,但是变化的趋势一点都不慢,而是以一个指数增加的方式快速到达一半窗口处,然后开始减缓发送。前面是每收到一个ack,cwnd就增加1,后面是每个往返cwnd增加1.

快速重传与快速恢复

第22章 TCP的坚持定时器


我们知道,发送方每向接收方发送一个报文,都会接收到接收方的确认,在确认报文中,包含了窗口大小。现在,假设接收方的确认报文丢失了,那么发送方就会因为收不到确认而苦苦等待;发送方也因为接收不到数据而无事可做,这就会导致连接中断。为了防止这种情况的发生,发送方使用一个坚持定时器(persist timer)来周期性的向接收方查询,以便发现窗口是否已增大。
具体内容参考书上。

第23章 TCP的保活定时器


根据前面的介绍我们发现两个建立连接的主机相互之间不发送任何消息也是允许的,也就是说,自它们建立连接开始,中间的路由器无论是重启或是故障,只要两端的主机没有重启,那么这个连接就可以保持数天,数个月。然而,许多时候,一个服务器希望知道客户主机是否崩溃并关机或者崩溃又重新启动。保活定时器目的正在于此。
但是保活 选项也会带来一个问题,比如如果在中间一个路由器崩溃或重启时发送保活探查,那么TCP会认为客户主机已经崩溃,而实际并非如此。
另外一个例子是客户端向一个使用Telnet的主机注册时。如果客户端关机时,并没有注销,那么就会留下一个半开放的连接,而服务器又在等待客户的数据,则服务器永远等待下去。保活的功能就是试图在服务端检测这种半开放的连接。










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值