运输层
1、运输层协议概述
1.1、进程之间的通信
从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时,只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
1.1.1、运输层的功能
1、传输层提供进程和进程之间的逻辑通信(网络层提供主机之间的逻辑通信)
从IP层来说,通信的两端是两台主机。但“两台主机之间的通信”这种说法还不够清楚。严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。
从运输层的角度看,通信的真正端点并不是主机而是主机中的进程。 运输层提供应用进程间的逻辑通信。
“逻辑通信” 的意思是:从应用层来看,只要把应用层报文交给下面的运输层,运输层就可以把这报文传送到对方的运输层,好像这种通信就是沿着水平方向直接传送数据。但事实上这两个运输层之间并没有一条水平方向的物理连接(数据的传送是沿着图中的虚线方向经过多个层次传送的)。即“好像是这样通信,但事实上并非真的这样通信”。
也就是说,端到端的通信是应用进程之间的通信。网络层和运输层有明显的区别:网络层是为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信。
2、复用和分用
在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。这表明运输层有一个很重要的功能——复用 (multiplexing)和分用 (demultiplexing)。 例如一家四口都要给好友写信,统一放到邮筒里,邮政员一起送出去,这是复用。收到回信后,快递员把信分别给我们,这是分用。快递员就充当了传输层的角色。
3、传输层对收到的报文进行差错检测
网络层学过首部校验和,但是首部校验和只是校验首部,没有校验数据部分。因此需要传输层对数据进行检错。可以看出,传输层和网络层一起实现了可靠传输。但是传输层不一定实现可靠传输,要看是哪种协议。
1.2、运输层协议与网络层协议的主要区别
运输层向高层用户屏蔽了下面网络核心的细节 (如网络拓扑、所采用的路由选择协议等),它使应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道,但这条逻辑通信信道对上层的表现却因运输层使用的不同协议而有很大的差别。
- 当运输层采用面向连接的 TCP 协议时,尽管下面的网络是不可靠的,但这种逻辑通信信道就相当于一条全双工的可靠信道。
- 当运输层采用无连接的 UDP 协议时,这种逻辑通信信道仍然是一条不可靠信道。
1.3、运输层的两个主要协议
面向连接的传输控制协议TCP:
TCP 传送的数据单位协议是 TCP 报文段(segment)。 传送数据之前必须建立连接,数据传送结束后要释放连接。不提供广播或多播服务。由于TCP要提供可靠的面向连接的传输服务,因此不可避免增加了许多开销:如确认、流量控制、计时器及连接管理等。可靠,面向连接,时延大,适用于大文件。
无连接的用户数据报协议UDP:
UDP 传送的数据单位协议是 UDP 报文或用户数据报。 传送数据之前不需要建立连接,目的主机收到UDP报文后也不需要给出任何确认。虽然udp不提供可靠交付,但某些情况下UDP却是一种最有效的工作方式,比如说视频网站,视频的缓冲。 不可靠,无连接,时延小,适用于小文件。例如微信发信息。
1.4、运输层的寻址与端口
复用: 应用层所有的应用进程都可以通过传输层再传输到网络层。
分用: 传输层从网络层收到数据后交付指明的应用进程。
通信过程分析:如果要发送数据给一个主机,只需要知道它的IP地址,就能寻找到主机所在的网络;进入所在网络后可以根据MAC地址定位到具体的主机(网络层);找到主机后,还需要找到主机中接收该数据的进程(传输层)。如何找到该进程呢?—————根据端口(逻辑端口)
端口: 端口是传输层的SAP(服务访问点/接口),标识主机中的应用进程。该端口为逻辑端口/软件端口,要和硬件端口区分开,像路由器、交换机这种直接插上去的端口称为硬件端口。
端口号: 端口由具体的数字标识叫做端口号,端口号只有本地意义,在因特网中不同计算机的相同端口是没有联系的。
(按照范围0-65535分类)两大类端口:
端口号范围:端口号长度为16bit,能表示2^16=65536个不同的端口号。
(1) 服务器端使用的端口号
- 熟知端口,数值一般为 0~1023。给TCP/IP最重要的一些应用程序,让所有用户都知道
- 登记端口号,数值为 1024~49151,为没有熟知端口号的应用程序使用的。使用这个范围的端口号必须在 IANA 登记,以防止重复。
(2) 客户端使用的端口号
- 又称为短暂端口号,数值为 49152~65535,仅在客户进程运行时才动态选择,留给客户进程选择暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的动态端口号。通信结束后,这个端口号可供其他客户进程以后使用。
常用的熟知端口
| 应用程序 | FTP | TELENT | SMTP | DNS | TFTP | HTTP | SNMP | HTTPS |
|---|---|---|---|---|---|---|---|---|
| 熟知端口号 | 21 | 23 | 25 | 53 | 69 | 80 | 161 | 443 |
- TFTP( 简单文件传输协议:Trivial):69岁退休;
- SNMP(简单网络管理协议:Simple Network Management Protocol):在161医院要死了。
1.5、套接字
在网络中采用发送方和接收方的套接字组合来识别端点,套接字唯一标识了网络中的一个主机(IP地址标识网络中每一个主机)和它上面的一个进程(端口号标识主机中的进程)。
套接字 Socket= ( 主机IP地址,端口号Port):根据IP地址可以找到主机(MAC地址(标识数据链路层上每一个设备/网卡)也是根据IP地址找到的),根据端口号可以找到主机中的具体进程。
2、用户数据报协议UDP
2.1、UDP概述
UDP只在IP数据报服务之上增加了很少功能,即复用分用和差错检测功能。虽然 UDP 用户数据报只能提供不可靠的交付,但 UDP 在某些方面有其特殊的优点
UDP的主要特点:
(1)UDP 是无连接的,发送数据之前不需要建立连接,,因此减少了开销和发送数据之前的时延。
(2) UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表(由应用层保证可靠交付)。
(3) UDP是面向报文的,适合一次性传输少量数据的网络应用。(应用层给UDP多长的报文,UDP就照样发送,即一次发一个完整报文。在传输层称为报文段。如果数据太大,在传给网络层时还要分片,所以适合一次传输少量数据。)
(4) UDP 没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很适合多媒体通信的要求。
(5) UDP 支持一对一、一对多、多对一和多对多的交互通信。
(6) UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要短。
2.2、UDP首部格式
用户数据报 UDP 有两个字段:数据字段和首部字段。首部字段有 8 个字节,由 4 个字段组成,每个字段都是 2 个字节。
- 源端口号:可有可无,在需要对方回信时选用。不需要时可用全0.
- 目的端口号:在终点交付报文时必须要使用到。
- UDP长度:UDP数据报的长度(包括首部和数据),其最小值是8B(仅有首部)。
- UDP校验和:检验UDP数据报在传输中是否有错。有错就丢弃。该字段是可选的,当源主机不想计算校验和时,则直接令该字段为全0。
- 伪首部:伪首部只有在计算检验和时才出现,不向下传送也不向上递交。伪首部伪的就是IP数据报的首部。
- 0字段:固定部分,全0。
- 17字段:封装UDP报文的IP数据报首部协议字段是17。(IP数据报首部的协议字段,在说明数据部分使用的是什么协议。)
当运输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交应用进程
因此如果接收方 UDP 发现收到的报文中的目的端口号不正确,就丢弃该报文,并由 ICMP 协议发送“端口不可达”差错报文给发送发。
请注意:虽然在UDP之间的通信要用到其端口号,但是由于UDP的通信是无连接的,因此不需要使用套接字来建立连接(TCP之间的通信必须要在两个套接字之间建立连接)
2.3、UDP校验
如何用伪首部校验UDP数据报有没有发送差错:
在计算检验和时,要在 UDP 用户数据报之前增加 12 个字节的伪首部。这种伪首部不是 UDP 用户数据报真正的首部。只是在计算检验和时,临时添加在 UDP 用户数据报前面,得到一个临时的 UDP 用户数据报。检验和是按照这个临时的 UDP 用户数据报来计算的。伪首部既不向下传送也不向上递交,仅仅是为了计算检验和。
UDP 计算检验和的方法和计算 IP 数据报首部检验和的方法相似。不同的是:UDP 的检验和是把首部和数据部分一起都检验。
计算 UDP 检验和的例子
在发送端:
- 填上伪首部(伪首部只有在计算检验和时才出现)
- 先首部校验和字段填充全0
- 全0填充数据部分(目的是要让UDP数据报要看成许多4B(16位)的字串接起来)
- 伪首部+首部+数据部分采用二进制反码求和(此时校验和字段全0)
- 把和求反码填入检验和字段
- 去掉伪首部,发送
在接收端:
- 填上伪首部
- 伪首部+首部+数据部分采用二进制反码求和(此时校验和字段有值)
- 结果全为1则无差错,否则丢弃数据报/交给应用层附上出差错的警告。
这种简单的差错检验方法的检错能力并不强,但它的好处是简单,处理起来较快。
3、传输控制协议TCP
3.1、TCP最主要的特点
- TCP是面向连接(虚连接,并不是物理连接)的运输层协议。也就是说,应用程序在交互时必须先建立连接,交互完成后必须要断开连接。
- 每一条 TCP 连接只能有两个端点 (endpoint),每一条 TCP 连接只能是点对点的(一对一)。
- TCP 提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。可靠有序,不丢不重
- TCP 提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。
- 在发送时,应用程序把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。
- 在接收时,TCP把收到的数据放入到缓存中,上层的应用程序在合适的时候读取缓存中的数据。
- 面向字节流。TCP 中的“流”(stream)指的是流入或流出进程的字节序列。“面向字节流”的含义是:虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流,字节流中的每一个字节都按顺序编号。
发送缓存:准备发送的数据&已发送但尚未收到确认的数据 接收缓存:按序到达但尚未被接受应用程序读取的数据&不按序到达的数据
3.2、TCP面向流的概念
TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。
图中的TCP连接是一条虚连接(逻辑连接),而不是一条真正的物理连接。TCP报文段先要传送到IP层,加上IP首部后,再传送到数据链路层。再加上数据链路层的首部和尾部后,才离开主机发送到物理链路。
TCP和UDP在发送报文时所采用的方式完全不同。TCP并不关心应用进程一次把多长的报文发送到TCP的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP发送的报文长度是应用进程给出的)。
- 如果应有进程传送到TCP缓存的数据块太长,TCP就可以把它划分短一些再传送。
- 如果应用进程一次只发送一个字节,TCP也可以等待积累有足够多的字节后再构成报文段发送出去。
3.3、TCP报文段首部格式(重点,单位4B)
TCP虽然是面向字节流的,但是TCP传送的数据单元缺失报文段,一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它首部中各字段的作用。TCP报文段首部的前20个字节是固定的(对应图中的前5行:4bytes*5=20bytes),后面有4n字节是根据需要而增加的选项。因此TCP首部的最小长度是20字节。
首部固定部分各个字段意义如下:
- 源端口:2B
- 目的端口:2B
- 序号seq(sequencer:n. 音序器):4B;在一个TCP连接中传送的字节流中的每一个字节都按顺序编号,本字段表示本报文段所发送数据的第一个字节的序号。(一起来吃饭的一组人按顺序每个人分个号,但进去的时候只看第一个人的序号) TCP头就是TCP首部,序号字段表示的是报文段中第一个字节的序号。
- 确认号ack:4B;期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,则证明到序号N-1为止的所有数据都已正确收到。(服务员确认一下下一组人的第一个人是几号),接收端TCP缓存中已经存入123字节,然后返回一个确认报文段,确认报文段首部有一个字段为确认号字段,接下来希望收到4号字节,所以确认号字段填4。
- 数据偏移(首部长度) : 4位;TCP报文段的数据起始处距离TCP报文段的起始处有多远,以4B位单位,即1个数值是4B。 例如数据偏移是1111,10进制数是15,15*4B=60B。说明TCP首部长度为60B。
- 保留:占6位,保留为今后使用,但是目前应置为0
- 6个控制位:用来说明本报文段的性质,如下字段所示
- 紧急位URG(urgency:n紧急):URG=1时, 标明此报文段中有紧急数据,是高优先级的数据,应尽快传送,不用在缓存里排队,配合紧急指针字段使用。(这组人有会员,先进去)
- 确认位ACK:ACK=1时确认号有效,在连接建立后所有传送的报文段都必须把ACK置为1。(拿到号后,服务员必须给号盖章)
- 推送位PSH:PSH=1时, 接收方尽快交付接收应用进程,不再等到缓存填满再向上交付。(进去以后,有一组人很急,要先吃)
- 复位RST(rest:重置):RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立传输链接。(之前号码作废,重新取号)
- 同步位SYN(synchronous:同步的): SYN=1时,表明是一个连接请求报文或连接接受报文。(我和服务员说取个号/服务员把号给我)
- 终止位FIN:FIN=1时, 表明此报文段发送方数据已发完,要求释放连接。(一组人已经进去了,号可以作废了)
- 窗口:2B;指的是发送本报文段的一方的接收窗口,即现在允许对方发送的数据量。
- 检验和:2B;检验首部+数据,检验时要加上12B伪首部,第四个字段为6。
- 紧急指针:2B;URG=1时才有意义,指出本报文段中紧急数据的字节数。(是会员时,查看会员人数)
- 选项(长度可变):最大报文段长度MSS、窗口扩大、时间戳、选择确认...
- 填充:全0,保证TCP首部是4B的倍数,填充+选项=4B。
3.4、TCP连接
TCP连接的端点叫做套接字(socket)或者插口,根据定义:端口号拼接到IP地址即构成了套接字。因此,套接字的表示方法是在IP地址后面写上端口号,中间用冒号或逗号隔开。
每一条TCP连接唯一的被通信两端的两个端点(即两个套接字)所确定,即:TCP连接 ::= {socket1,socket2}
套接字socket = { IP地址:端口}
TCP连接的端点是一个很抽象的套接字(IP地址:端口),同一个IP地址可以有多个不同的TCP连接,而同一个端口号可以出现在多个不同的TCP连接中。
3.5、TCP连接管理
TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,TCP连接传输就有三个阶段,即:连接建立——数据传送——连接释放。TCP连接的管理就是使运输连接的建立和释放都能正常地进行。
TCP连接建立过程中要解决以下三个问题:
- 要使每一方能够确知对方的存在。
- 要允许双方协商一些参数(如最大报文段长度,最大窗口大小,服务质量等)。
- 能够对运输实体资源(如缓存大小,连接表中的项目等)进行分配。
3.5.1、TCP连接建立(三次握手)
TCP连接的建立采用客户服务器方式,主动发起连接建立的应用进程叫做客户(client),而被动等待连接建立的应用进程叫服务器(server)。
TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段。下图画出了三次握手建立的过程。
假设运行在一台主机(客户)上的一个进程想与另一台主机(服务器)上的一个进程建立一条连接,客户应用进程首先通知客户TCP,他想建立一个与服务器上某个进程之间的连接,客户中的TCP会用以下步骤与服务器中的TCP建立一条TCP连接,TCP连接建立过程:
- 服务器进程就处于LISTEN(收听)状态,等待客户的连接请求。如有,即作出响应。
- A 的 TCP 客户进程向 B 的TCP服务器进程发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
- SYN=1(同步位:SYN=1时,表明是一个连接请求/连接接受报文)
- seq=x(序号字段:随机分配,表示连接请求报文段第一个字节的序号)
- TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据(代表无应用层数据),但要消耗掉一个序号。这时,**TCP客户进程进入SYN-SENT(同步已发送)**状态,等待服务器B确认。
- B 的 TCP 收到连接请求报文段后,如同意建立连接,则向A发送确认。在确认报文段中应把SYN位和ACK位都置1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。
- 注意:这个SYN报文段也不能携带数据,但同样要消耗掉一个序号。这时TCP服务器进程进入SYN-RCVD(同步收到)状态。
- 服务器端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接,无应用层数据。
- ACK=1(确认位:ACK=1时确认号有效,连接建立后所有传送的报文段都必须把ACK置为1)
- seq=y(序号字段:随机分配,确认报文段也有序号字段)
- ack=x+1(确认号字段:因为客户端的连接请求报文段第一个字节的序号为x,表示期待客户端接下来的发送报文段的第一个字节的序号为x+1)
- TCP客户进程A收到B的确认报文段后,还要向B给出确认。确认报文段的ACK置1,确认号ack=y+1,而自己的序号seq=x+1。这时A 的 TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。
- TCP的标准规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下,下一个数据报文段的序号仍是seq=x+1。
- ack=y+1(确认号字段:因为服务端上次发来的确认报文段第一个字节序号是y,所以期待下一个服务端确认报文段的第一个字节的序号为y+1)
- B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。 也进入ESTABLISHED状态。
注意:在图中B发送给A的报文段也可拆分成两个报文段,可以先发送一个确认报文段(ACK=1,ack=x+1),然后再发送一个同步报文段(SYN=1,seq=y),这样的过程就变成了四次握手,但效果是一样的
为什么A最后还要发送一次确认? 主要是为了防止已失效的连接请求报文段突然又传送到了B【重传】,因而产生错误。
3.5.2、三次握手的意义
“三次握手” 的目的是为了防止已失效的链接请求报文突然又传送到了服务端,因而产生错误。
正常的情况: A 发出连接请求,但因连接请求报文丢失而未收到确认,于是 A 再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。A 共发送了两个连接请求报文段,其中第一个丢失,第二个到达了B。没有 “已失效的连接请求报文段”。
现假定出现了一种异常情况: 即 A 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 B。本来这是一个早已失效的报文段。但 B 收到此失效的连接请求报文段后,就误认为是 A 再次发出的一个新的连接请求。于是就向 A 发出确认报文段,同意建立连接。
假设不采用“三次握手”,那么只要 B 发出确认,新的连接就建立了。由于现在 A 并没有发出建立连接的请求,因此不会理睬 B 的确认,也不会向 B 发送数据。但 B 却以为新的运输连接已经建立,并一直等待 A 发来数据。这样,B 的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。
3.5.3、SYN洪泛攻击
SYN洪泛攻击发生在OSl第四层,这种方式利用TCP协议的特性,就是三次握手。攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包, 而当服务器返回ACK后, 该攻击者就不对其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送ACK给攻击者。这样更加会浪费服务器的资源。攻击者就对服务器发送非常大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上,这些TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,就无法为正常用户提供 服务了。
解决办法:设置SYN cookie
3.5.4、TCP的连接释放(四次挥手)
参与一条TCP连接的两个进程中的任何一个都能终止该连接,连接结束后,主机中的“资源”(缓存和变量) 将被释放。释放过程如下:
- 现在A和B都处于established状态。
- A的应用进程先向其TCP发出连接释放报文段,并停止在发送数据,主动关闭TCP连接。A把报文段首部位的终止控制位FIN置为1,其序号seq=u,它等于前面已传送过的数据的最后一个字节的序号加1。
- 这时A进入FIN-WAIT-1状态,等待B的确认。FIN报文段即使不携带数据,也消耗一个序号。
- B收到连接释放报文段后,即发出确认,确认号是ack=u+1,seq是v,等于前面B已传送过数据的最后一个字节的序号加1,然后B进入CLOSE-WAIT状态。
- TCP服务器进程这时候应通知高层应用进程,因而从A到B这个方向的连接就释放了,这时候TCP连接处于半关闭状态,即A已经没有数据要发送,B不会接收了,但B若发送数据,A仍要接收,B到A这个方向的连接并未关闭,这个状态可能会持续一段时间。
- A收到B的确认后,进入FIN-WAIT-2状态,等待B发出的连接释放报文段。
- 若B已经没有要向A发送的数据,应用进程就通知TCP释放连接。这时B发出的报文段FIN必须为1。假定B的序号为W(半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这时B进入LAST-ACK状态,等待A的确认。
- A收到B的连接释放报文段后,必须对此发出确认,在确认报文段中把ACK置为1,确认号ack=w+1,而自己的序号是seq=u+1。然后进入TIME-WAIT(时间等待)状态。
- 请注意,现在的TCP连接还没有释放掉。必须经过**时间等待计时器(TIME-WAIT timer)**设置的时间2MSL后,A才进入到CLOSED状态。时间MSL叫做最长报文段寿命(Maximum Segment Lifetime),通常是两分钟。
- 因此,A进入到TIME-WAIT状态后,要经过4分钟才能进入到CLOSED状态,才能开始建立下一个新的连接。
- 连接释放完毕
为什么A在TIME-WAIT状态必须等待2MSL时间?
- 为了保证A发送的最后一个ACK报文能够到达B。
- 这个ACK报文有可能丢失,因而使处于在LAST-ACK状态的B收不到A发送的FIN+ACK报文段的确认。
- B会超时重传这个FIN+ACK报文段,A就能在2MSL时间内收到这个重传的FIN+ACK报文段。
- 接着A重传一次确认,重新启动2MSL计数器。最后A和B都正常进入到CLOSED状态。如果A在TIME_WAIT状态不等一段时间而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN+ACK报文段。B就无法按照正常步骤进入CLOSED状态。
- 防止“已失效的连接请求报文段”出现在本连接中。
- A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。
- 这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。B只要收到了A发出的确认,就进入 CLOSED状态。
- 同样,B在撤销相应的传输控制块TCB后,就结束了这次的TCP连接。可以看到,B结束TCP连接的时间要比A早些。
理解: 确认号字段是对对方数据报序号的下一个期待。序号字段第一次由自己随机分配序号,在之后的互相发送过程中,序号字段按照对方期待的来填写。
3.5.5、保活计时器
如果已经建立了连接,但是客户端突然出现故障了怎么办?
- TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。
- 服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。
- 若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
3.6、TCP可靠传输
- 传输层: 使用TCP实现可靠传输(UDP依靠应用层实现可靠传输)
- 网络层: 提供尽最大努力交付,不可靠传输
- 可靠: 保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的。
3.6.1、可靠传输的工作原理
TCP 发送的报文段是交给 IP 层传送的。由于IP层只能提供尽最大努力服务,也就是说,TCP下面的网络层所提供的是不可靠传输。因此,TCP 必须采取适当的措施才能使得两个运输层之间的通信变得可靠。
理想的可靠传输必须满足以下两个条件。
- 传输信道不产生差错
- 不管发送方以多快的速度发送分组,接收方总是可以及时处理得到的数据。
然而实际的网络并不具备以上两个条件,因此,我们可以使用一些可靠的传输协议,当出现差错时让发送方重传出现差错的数据,同时,在接收方来不及处理收到的数据时,及时告知对方适当降低发送数据的速度。
3.6.2、TCP实现可靠传输的四种机制
1 校验:
与UDP校验一样,增加伪首部,通过使用二进制反码求和的方法来判断是否发生错误。
2 序号
虽然我们说TCP是面向字节流的,但是实际发送时,是把一些字节放一起组成报文段。报文段大小是不定的。
3 确认
- 发送方如何找到接收方正确完整接收到123报文段呢? ——确认机制。
- 接收方接收报文段后会返回一个确认报文段(首部确认号字段为4,期待下一个字节序号是4)。发送方收到确认报文段后,知道接收方正确接收了,就可以把123报文段从TCP缓存中删去。
- 发送方继续发送456、78报文段,而456报文段没到达接收方,TCP使用累计确认,所以接收方确认报文段的首部确认号字段仍然为4。
- 发送方接收到确认报文段后,会重传456报文段。接收方收到456报文段后,给发送方发送首部确认号为9的确认报文段。
4 重传
- 确认重传不分家,TCP的发送方在规定的时间(重传时间)内没有收到确认就要重传已发送的报文段。超时重传
- TCP采用自适应算法,动态改变重传时间RTTs(加权平均往返时间)。
- 发送第一个报文段时,RTTs取的是第一个报文段的RTT(从它发送到收到确认的时间);然后取第二个报文段的RTT......通过公式可以动态计算各报文段加权平均往返时间。
有没有什么办法,在超时事件发生之前,就知道发送方有没有丢失报文段,可以尽快重传?——冗余ACK(冗余确认)
冗余ACK(冗余确认):
每当比期望序号大的失序报文段到达时,发送一个冗余ACK,指明下一个期待字节的序号。
举例:发送方已发送1,2,3,4,5报文段
- 接收方收到1,返回给1的确认(确认号为2的第一个字节)
- 接收方收到3,仍返回给1的确认(确认号为2的第一个字节) :可以看到,如果发生了失序,还是按照失序前返回确认。
- 接收方收到4,仍返回给1的确认(确认号为2的第一个字节)
- 接收方收到5,仍返回给1的确认(确认号为2的第一个字节)
- 发送方收到3个对于报文段1的冗余ACK ——>认为2报文段丢失,重传2号报文段。称为快速重传技术,等下会讲到快重传和快恢复。
3.6.3、TCP的窗口和协议
滑动窗口,停等协议、GBN协议、SR协议等在链路层已经讲过,原理差不多。根据上面所讲的冗余确认可以看出,TCP常使用的是GBN、SR协议。
3.7、TCP流量控制
3.7.1、流量控制
流量控制: 让发送方发送速率慢点,要让接收方来得及接收。TCP利用滑动窗口机制实现流量控制。
在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口rwnd (接收方设置确认报文段的窗口字段来将rwnd通知给发送方),发送方的发送窗口去接收窗口rwnd和拥塞窗口cwnd的最小值。
3.7.2、流量控制过程
A向B发送数据,连接建立时,B告诉A:“ 我的rwnd=400 (字节)”,设每一个报文段100B,报文段序号初始值为1。
TCP采用的是累计确认,并不使用停等协议。主机A给B发送了几个报文段,主机B才给A发送一个确认报文段。TCP流量控制可以看做累计确认+SR选择重传协议+动态调整接收窗口。
主机B给主机A发送确认报文段中窗口字段为rwdm=0(零窗口)时,主机A不能再发送数据给主机B,而主机B又在等主机A发送数据,于是主机A和B互相死等,此时就会造成类似操作系统中的死锁现象。如何解决?——持续计时器
3.7.3、持续计时器
- TCP为每一个连接设有一个持续计时器,只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。
- 若持续计时器设置的时间到期,就发送一个零窗口探测报文段。接收方收到探测报文段时给出现在的窗口值。
- 若窗口仍然是0, 那么发送方就重新设置持续计时器。
- 在持续计时器设置的时间内,接收方有可能会给发送方一个非零窗口通知。
3.8、TCP拥塞控制
3.8.1、拥塞控制
出现拥塞的条件: 对资源需求的总和>可用资源
拥塞导致的问题: 网络中有许多资源同时呈现供应不足——>网络性能变坏——>网络吞吐量将随输入负荷增大而下降
拥塞控制目的: 防止过多的数据注入到网络中。这是一个全局性问题。
拥塞控制与流量控制的区别: 拥塞控制是多台主机同时使用网络资源给一个接收方发送数据,使得网络非常繁忙,接收方不知道是哪个主机的问题,拥塞控制是一个全局性问题。流量控制是点对点问题,让发送方发慢点。
3.8.2、拥塞控制四种算法
四种算法:
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
为了方便讨论,假定如下:
- 数据单方向传送,而另一个方向只传送确认报文(实际传输数据是双向的)
- 接收方总是有足够大的缓存空间,因而发送窗口大小取决于拥塞程度
- 前面学过,发送窗口=Min{接收窗口rwnd,拥塞窗口cwnd},这里假设接收窗口足够大,因而发送窗口大小取决于拥塞程度。
接收窗口与拥塞窗口区别:
- 接收窗口: 接收方根据接受缓存设置的值,并告知给发送方,反映接收方容量。
- 拥塞窗口: 发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量。
3.8.3、慢开始和拥塞避免算法
拥塞窗口最开始的初始值: 默认为1即cwnd=1,为了讨论方便,这里1不是一个字节而是一个报文段,报文段的长度是一个最大报文段长度MSS。
慢开始算法: 拥塞窗口指数规律增长,拥塞窗口在发送方收到确认报文时增长。
ssthresh值: 拥塞窗口增加到ssthresh(慢开始限值)的初始值后,开始执行拥塞避免算法。并且新的ssthresh值是发生网络拥塞时窗口的一半。
拥塞避免算法: 每次到达ssthresh值后,线性增加拥塞窗口。
网络拥塞: 发生拥塞后拥塞窗口马上降为初始值cwnd=1。
一个传输轮次:
- 发送了一批报文段并收到它们的确认的时间。
- 一个往返时延RTT。
- 开始发送一批拥塞窗口内的报文段到开始发送下一批拥塞窗口内的报文段的时间。
- 每经过一个传输轮次,拥塞窗口CWD就加倍
3.8.4、快重传和快恢复算法
快重传: 发送方收到3个重复的冗余ACK ——>认为该报文段丢失,重传该报文段。在超时计时器之前执行快重传可以实现快速重传报文段。
快恢复: 发生拥塞后不会像慢开始一样拥塞窗口降为初始值,而是降到新的ssthresh值。
拥塞避免: 快恢复后继续执行拥塞避免,线性增加拥塞窗口。