【笔记整理 - 计算机网络】

资料来源:《计算机网络 自顶向下方法》

应用程序通信的本质:不同的端系统间的进程交换报文。

套接字:应用层与运输层之间的接口,应用程序通过它发送报文。

在因特网中,主机通过IP地址标识,而主机中的进程通过端口号标识。

————应用层协议————

HTTP和Web

超文本传输协议(HyperText Transfer Protocol,HTTP),是Web的核心。

HTTP使用TCP作为它的支撑运输协议。

客户端向套接字接口发送HTTP请求报文,从中接收HTTP响应报文。服务器同理。

HTTP有自己的任务,数据丢失、乱序等问题都交给TCP协议来解决。

HTTP是无状态协议。意思是它不会存储任何客户相关的信息,如果客户端在短时间内多次请求同一个对象,则服务器全都做出响应。

HTTP仅定义HTTP客户端HTTP服务器间的通信协议。不关心浏览器如何解释接受到的Web页面。


Web术语

Web页面由对象组成;

一个对象就是一个文件,诸如一个 HTML文件、JPEG图形、Java小程序、视频片段 等。

对象可以通过一个URL地址寻址。

多数Web页面含有一个HTML基本文件及几个引用对象。(1个Web页面包含1个HTML文本、5个JPEG图形,那么这个Web页面有6个对象)

HTML文件通过对象的URL地址引用其他对象。

一个URL地址由2部分组成:主机名+对象路径名。

// 似乎并不准确,但大概就这意思
https://space.bilibili.com/402417817/dynamic
space.bilibili.com 是主机名
/402417817/dynamic 是路径名

Web浏览器:实现了HTTP的服务器端

Web客户端:实现了HTTP的服务器端,存储Web对象,每个对象有URL寻址。


持续链接和非持续连接的问题:

  • 是所有请求都通过同一个TCP连接发送;

  • 还是对每个请求使用单独的TCP连接发送?

HTTP对二者都支持。

非持续连接的HTTP

请求的Web页面有多少个对象,就建立多少个TCP连接。

TCP连接可以串行,也可以并行。

所有对象在正式开始传输前,都得经历3次握手,等待2RTT时间。

持续连接的HTTP

一个Web页面的所有对象都通过一个TCP连接发送。更有甚者,一个用户的多个Web页面都通过一个TCP连接发送。

HTTP的默认模式是使用带流水线的持续连接。


HTTP 报文格式

一个典型的HTTP请求报文:P.67 和 P.68 的2张图。

GET /somedir/page.html HTTP/1.1	// 请求行
Host: www.someschool.com.edu	//余下的都是首部行
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr
// 为实体体空出一行。GET方法中不存在
// 实体体,只有在使用POST方法是才会用到。GET方法中不存在
方法 URL 版本
首部字段名: 值
...

实体体

提交数据不一定要用到POST方法:使用GET方法,将提交的数据信息作为URL的一部分传给服务器。

HTTP响应报文

HTTP/1.1 200 OK		// 状态行。余下的都是首部行
Connection: close
Date: Tue, 18 Aug 2015 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Connect-Length: 6821
Connect-Type: text/html

(date date date date date ...)
// 实体体是报文的主要部分,就是请求对象本身,可以是HTML文件、图片、视频...

常见状态码:

  • 200 OK :请求成功,信息在响应报文中。
  • 301 Moved Permanently:请求对象已经被永久转移了,新的URL定义在响应报文的Location:首部行中。客户端软件将自动获取URL。
  • 400 Bad Request:一个通用差错代码,只是该请求无法被服务器理解。
  • 404 Not Found:请求的文档不在服务器上。
  • 505 HTTP Version Not Supported:服务器不支持请求报文使用的HTTP协议版本。

客户端/服务器如何决定HTTP中有哪些首部行?设计的因素很多,书中没展开。



cookie

HTTP是无状态协议,为了识别、追踪用户,引入了cookie。

cookie有4个组件:

  • HTTP请求报文中的cookie首部行;
  • HTTP响应报文中的cookie首部行;
  • 客户端保留有一个cookie文件,由浏览器管理;
  • 服务器的一个后端数据库中。

工作流程:

  • 用户访问Web站点,Web服务器识别该用户,在后端数据库生成一个表项;

  • Web服务器的响应报文中包含了为该用户新生成的识别码,位于Set-cookie:首部行中;

  • 客户浏览器接收响应包,将cookie识别码、服务器主机名记入cookie文件中;之后用户在浏览该Web站点时,每请求一个Web页面,就会从cookie文件中抽取识别码,放入HTTP请求报文的Cookie:首部行中;

通过这种方式,服务器就能追踪用户按什么顺序、什么时间访问了哪些页面。

cookie识别码保存在 客户端文件/服务器数据库 中,不会随TCP连接的断开而失效。



Web缓存

Web 缓存器(Web cache)也叫做代理服务器(proxy server)。

作为客户端与服务器的中介,分担服务器的流量,并提升用户体验。

工作流程:

浏览器向Web缓存器创建TCP连接,请求Web对象;

如果Web缓存器中有该对象,就返回对象;否则,Web缓存器连接Web服务器,请求该对象;

Web缓存器收到Web服务器的响应时,在本地存储一份副本,并向客户端返回副本。

Web缓存器通常由ISP购买并安装。通常Web缓存器与客户之间的链路状态更好,因此比客户直接连接Web服务的性能更好。

隐患:Web缓存器的内容过期

通过HTTP的条件GET方法解决:

Web缓存器每次收到客户端的请求,都会以GET方法向Web服务器发送一个带有If-Modified-Since: 首部行的报文。

首部行内容为文件的最后修改日期

如果文件没有被修改,Web服务器返回 304 Not Modified 报文。

(书中没提到如果文件被修改的操作,可能是像普通的响应报文那样返回对象?)


HTTP 流

视频作为普通文件存储在 HTTP 服务器中,客户端用 GET 方法请求视频文件 URL ,视频流输入客户端的缓存,缓存大小达到设定值后,播放视频。


DASH

经HTTP的动态适应性流(Dynamic Adaptive Streaming over HTTP)

在 DASH 中,视频编码为几个不同的版本,每个版本的视频清晰度不同。客户端动态地请求来自不同版本且长度为几秒的视频段数据块,网速好,质量好,网速差,质量差,一个视频块通过一个HTTP GET请求报文申请。

每个视频版本存储在 HTTP 服务器中,每个版本对应一个 URL 。

HTTP服务器有一个告示文件,客户端先请求告示文件,再根据速率决定算法来决定请求下一次 HTTP GET 请求哪个版本的视频块。


SMTP

简单邮件传输协议(Simple Mail Transfer Protocol, SMTP)

由3部分组成:用户代理、邮件服务器、SMTP

SMTP 使用 TCP 服务。邮件服务器可作为客户端,又可作为服务器。

互联网刚出现时,电子邮件就已成为流行的应用程序,这使得 SMTP 保留有旧时代的限制。

SMTP 限制所有邮件报文只能采用简单地7Byte ASCII 表示(当年的传输能力只支持文字)。

所以在使用 SMTP 传输邮件之前,需要将二进制数据编码为 ASCII 码,传输后要进行解码还原。


邮件收发过程:

用户—用户代理——邮件服务器—(SMTP)—邮件服务器——用户代理—用户

简单来说,

1、发送方通过邮件代理程序将邮件和相关信息提交给邮件服务器

2、邮件服务器之间建立 TCP 连接,发送邮件;

3、接收方在方便的时候调用邮件代理程序邮件服务器上获取邮件。

邮件的发送、接收都是由邮件服务器完成的。

两端的邮件服务器直接连接,无论服务器的距离有多远。

P.78 介绍有应用层层面的握手协议,不知道是帮助理解的伪代码还是真的握手过程。


与 HTTP 的对比

1、

SMTP 是一个推协议发送邮件服务器将文件推向接收邮件服务器。TCP 连接由想发送文件的机器发起的。

HTTP 是一个拉协议,用户在方便的时候,从服务器拉取信息到本地,TCP 连接由想接收文件的机器发起的。

2、

SMTP 要求报文采用7比特 ACSII 码格式,不符合格式的数据在发送前需要进行编码转换;

HTTP 不受这种限制。

3、

SMTP 把所有报文对象放在一个报文中;

HTTP 把每个对象分别封装在各自的 HTTP 响应报文中。


邮件报文格式

信件上通常要包含双方地址、发送日期等等信息。

电子邮件中这些信息作为环境首部信息,位于报文体前面,包括在一系列首部行中,格式由 RFC 5322 定义。

每个收不必须含有一个 From: 和一个To:,其余的都是可选项。

例子:

From: alice@crepes.fr
To: bob@hamburger.edu
Subject: Searching for the meaning of life
// 一行空白行
// ACSII 格式的报文体


邮件访问结构和协议

已知邮件并不是从一台用户主机直接发往另一台主机,而是按如下结构发送的:

发送者—邮件代理——邮件服务器——邮件服务器——邮件代理—接收者

结构:

对于接收方:为了能及时接收任何时候到达的新邮件,接收方邮件服务器必须时刻在线,这就使得邮件服务器软件不能部署在用户主机上,必须部署于专门的邮件服务器中,其通常由 ISP 提供。

对于发送方:发送者的主机将邮件提交给服务器后,服务器可以在多个时段重复尝试发送邮件,确保邮件正确发送。而这一工作也是需要服务器长时间运行,不可能交由用户主机来完成。

以前是用户登录到邮件服务器,运行服务器中的应用程序来读取邮件;

现在邮件的访问使用了 客户-服务器 体系结构。

协议:

发送者—邮件代理——邮件服务器: SMTP 协议;

邮件服务器——邮件服务器: SMTP 协议;

邮件服务器——邮件代理—接收者: 取报文是一个拉操作,有 POP3、IMAP、HTTP

前2个感觉用的不多了,没有详细了解

POP3
IMAP

POP3 客户端对邮件的修改不会反馈到服务器上,IMAP 会。

HTTP

基于Web的电子邮件现在使用得越来越多,用户代理就是普通的浏览器,而浏览器与邮件服务器之间的通信就通过 HTTP 进行。用户将邮件发往邮件服务器时使用的也是 HTTP 协议。


DNS

域名系统(Domain Name System,DNS)

因特网中的一台主机可以用主机名(hostname)来标识。如www.google.com等,名字方便记忆;

主机也可以使用 IP地址 来标识。IP地址长度固定,机器容易处理,并提供了主机在因特网中的位置信息。

DNS的意义:

人类容易记忆主机名,IP地址方便机器处理。

DNS的作用是提供将主机名转换为相应的IP地址的目录服务。

DNS是什么:

  1. 一个有分层的DNS服务器实现的分布式数据库;
  2. 一个使得主机能查询分布式数据库的应用层协议

DNS 运行在 UDP协议之上,使用53号端口。

作用:

1、用户主机上运行有DNS应用的客户端;

2、用户在浏览器中输入主机名,浏览器抽取主机名,将其传给DNS客户端;

3、DNS客户端 向 DNS服务器 发送含有主机名的请求;

4、DNS服务器 返回带有 IP地址 的请求;

5、浏览器接收 IP地址,向该地址的80端口进程发起 TCP 连接。

别的服务:

  • **主机别名:**一些较复杂的主机名例如 relay1.west-cost.enterprise.com 可能还有其它别名 enterprise.comwww.enterprise.com。DNS 可以通过主机别名来获得完整的规范主机名和 IP地址。
  • **邮件服务器别名:**同上。
  • **负载分配:**在冗余的服务器之间进行负载分配。例如有一个Web站点冗余分布在多台服务器上,每台服务器有各自的IP地址。DNS数据库中存储这些IP地址的集合,一个IP地址集合与一个规范主机名相联系。

DNS的实现

最简单的设计是在因特网上只使用一个 DNS服务器,该服务器包含所有映射,而在现实中这是行不通的,现实中的DNS服务器采用了分布式设计,是一个在因特网上实现分布式数据库的典范。

有3种类型的DNS服务器:根DNS服务器、顶级域(Top-Level Domain,TLD)DNS服务器、权威DNS服务器。

大量的DNS服务器以层次方式组织,像一个树形结构。根结点为根DNS服务器;中间层节点为顶级域DNS服务器;叶结点为权威DNS服务器

  • 根DNS服务器:(书中没举例内容)提供TLD服务器的IP地址。
  • TLD服务器:com、org、net、edu这些就是顶级域,cn、uk、fr、jp这些是国家的顶级域。提供权威DNS服务器的IP地址。
  • **权威DNS服务器:**在因特网上拥有公共可访问主机的所有组织机构都必须提供公共可访问的DNS记录,这些记录将主机名映射为IP地址。

**本地DNS服务器:**不属于DNS服务器的层次结构,但很重要。每个ISP都有一台本地DNS服务器。当用户与ISP连接时,很容易就获取到本地DNS服务器。

本地DNS服务器通常邻近用户主机,在用户主机发出DNS请求时,其代理的作用,将请求转发到DNS服务器层次结构中。

一个查询例子

用户主机名cse.nyu.edu,用户的本地DNS服务器dns.nyu.edu;主机gaia.cs.umass.edu,权威服务器dns.umass.edu

主机cse.nyu.edu想知道主机gaia.cs.umass.edu的IP地址。

(迭代查询)

1、主机向本地DNS服务器提交含有gaia.cs.umass.edu的查询报文;

2、本地DNS服务器将该报文转发到根DNS服务器

3、根DNS服务器注意到edu前缀,向本地DNS服务器返回负责eduTLD服务器IP地址列表

4、本地DNS服务器向其中之一发送查询报文;

5、TLD服务器注意到umass.edu前缀,用权威DNS服务器的IP地址响应;

6、本地DNS服务器直接向权威DNS服务器 dns.umass.edu发送查询报文;

7、权威服务器将主机gaia.cs.umass.edu的IP地址返回;

8、本地DNS服务器向用户主机cse.nyu.edu返回结果。

一共4份查询报文和4份响应报文。

实际上TLD服务器不一定能直接定位到权威DNS服务器,在上面的例子中,大学的每个系还能细分,名称为dns.umass.edu的服务器接收到本地DNS服务器的请求,注意到cs.umass.edu前缀,然后返回的才是目标主机的权威服务器本地DNS服务器再向该服务器请求才能真正获得目标主机IP地址。

**迭代查询:**上方所示的例子,本地DNS服务器向多个服务器发送请求。接收到请求的服务器告诉它:“到...地方去找下一台服务器,别的我不管了。”

**递归查询:**像用户主机将请求交给本地DNS服务器一样,请求层层递交:本地DNS -> 根DNS -> TLD -> 权威DNS。权威DNS服务器返回的结果又层层返回本地DNS <- 根DNS <- TLD <- 权威DNS


DNS缓存

为了减少时延,DNS广泛使用了缓存技术。本地DNS服务器接收到任何一个回答,就能缓存回答中的信息。

DNS记录和报文

记录:

DNS数据库存储的是资源记录(Resource Record,RR),提供了主机名到IP地址的映射。

RR类型:( Name, Value, Type, TTL )

**TTL:**记录的生存时间,时间到期后就从缓存中删除。

Name和Value的值取决于Type:

  • **Type = A:**Name 是主机名,Value 是该主机名对应的 IP地址(relay1.bar.foo.com, 145.37.93.126, A)
  • Type = NS:Name 是个域(如 foo.com),Value 是个知道如何获得该域中主机IP地址的权威DNS服务器的主机名。(foo.com, dns.foo.com, NS)
  • Type = CNAME:Value 是别名为 Name 的主机对应的规范主机名(foo.com, relay1.bar.foo.com, CNAME)
  • Type = MX:Value 是别名为 Name 的邮件服务器规范主机名(foo.com, mail.bar.foo.com, MX)

报文格式:

P.90

这些记录是如何进入数据库的?

假设要注册一个网站:

1、向注册登记机构申请域名;

2、注册时提供基本和辅助权威DNS服务器的名字和IP地址。这2个权威DNS服务器的每一个,该注册机构都确保将一个类型NS和一个类型A的记录输入TLD com服务器:

(networkutopia.com, dns1.networkutopia.com, NS)

(dns1.networkutopia.com, 212.212.212.1, A)

P2P

以 BitTorrent 为例作介绍。

洪流:参与一个特定文件分发的所有对等方的集合。

在洪流中的对等方彼此下载等长度的文件块(典型长度为256KB)。

当一个对等方刚加入洪流时,它没有块,随着时间推移,它积累越来越多的块。

一个对等方下载块的同时,也在为其它对等方上载了块。

对等方能随时出入洪流,不受限制。在一个对等方获得了整个文件后,可以立即离开,也可以无私地留下来向洪流中的其它对等方上载块。

每个洪流都有一个基础设施节点:追踪器

当一个对等方加入洪流时,主动向追踪器注册自己,并周期性地通知追踪器它仍在洪流中。


收发流程、决策

当一个新的对等方Alice加入洪流时,追踪器随机从参与的对等方集合中选择一个子集,将子集中的所有对等方IP地址发给Alice;

Alice尝试对子集中的所有对等方建立TCP连接,成功连接TCP建立的对等方就成为邻近对等方;

洪流中的任一对等方都可以随时加入、离开与Alice的连接,即使它不在最初的那个子集中。

Alice获得了一个邻近对等方的集合后:

周期性地向对等方询问它们所具有的文件块列表,获得回应后,根据回应的信息作出决策;

决策1:如何向邻居(邻近对等方)请求块?

最稀缺优先:针对Alice没有的块,确定在邻居中副本数量最少的块,并请求那些最稀缺的块。

其目标是大致地均衡每个块在洪流中的副本数量。(申请后就在自己电脑中多了一个块副本,使得最稀缺块的数量优先提高。)

决策2:如何回应邻居的请求?

一报还一报:Alice每过10秒,测量出以最高速率向她提供数据的4个邻居(这4个对等方称为疏通);每过30秒,随机地从疏通中选择另一个邻居并向其发送块。


套接字编程

UDP:P.106

TCP:P.110

实际编程相关的,需要时作参考。

————运输层协议————

为运行在不同主机上的进程间提供逻辑通信功能。

逻辑通信:就是运行不同进程的主机好像直接相连一样。

运输层分组被称为报文段

运输层协议只工作在端系统中。

书中做了一个比喻,相当于一个大家庭里一个专门负责 收集/分发 所有家庭成员的信件的孩子。

将这个比喻继续延伸:运输层有许多不同的协议,如可靠的TCP、不可靠的UDP;家庭里有的孩子认真、有的孩子粗心……不同的协议提供不同的服务类型。

运输层协议能保证的服务仅限于端系统,且能弥补底层网络层协议的不足。

一个场景:

在使用电脑时,可能会同时打开多个使用网络的应用程序,它们通过不同的应用层协议使用网络。这时候电脑中就拥有多个不同的套接字。

运输层没有直接将数据交给应用层进程,而是交给了套接字。

运输层的工作

**多路分解:**将运输层中的数据交付到正确的套接字中;(获取,分发)

**多路复用:**将从应用层接收的数据块封装上首部信息,然后将封装成的报文段传递到网络层。(收集,发送)

多路复用的要求

括号内为自己的补充

  • 套接字有唯一标识符;(复用阶段:因为有多个套接字同时存在,为了能作出区分)

  • 每个报文段有特殊字段,来指示该报文段要交付到的套接字。(分解阶段:运输层接收到数据报,要上交给合适的套接字)


端口号

用于区分不同套接字的字段就是源端口号字符目的端口号字段

每个套接字都能分配一个端口号。

端口号是一个16位的数,大小在0~65535之间。

0~1023 范围的端口号是周知端口号,被保留给众所周知的协议使用。1024及以上的端口号能随意使用。


TCP 与 UDP 的套接字区别

UDP 套接字通过一个二元组来标识:目的IP地址、目的端口号

TCP 套接字通过一个四元组来标识:源IP地址、源端口号、目的IP地址、目的端口号

理解:TCP 经常要回复 ACK 号向通信对象确认,所以记录了源IP地址和源端口号,能很方便地做出回应。

套接字是个很常见的东西,在Web服务器中,对于每个新的请求,服务器都创建一个套接字用于连接。

UDP

提供最小服务,没有握手过程、不可靠。

设想一下设计一个最简单的运输层协议

在发送方:直接将应用层数据传给网络层;

在接收方:直接将网络层数据交给应用程序。

而这是行不通的,为了正确地在应用程序和网络层之间传递数据,也至少要最低限度的提供复用/分解服务

UDP 除了复用/分解服务以及少量的差错检测外,几乎没有对 IP 增加别的东西,使用 UDP 协议的应用程序开发人员基本上是在直接与 IP 打交道。

UDP 较 TCP 的优势

  • **应用层能更精细地控制数据的发送时机:**UDP收到数据就会立即将其打包发送;而 TCP 因为有拥塞控制机制,以及确认机制,所以时效性较差。
  • **无连接:**不需要先进行3次握手。
  • **无连接状态:**没有连接,也就不需要维持连接状态。连接状态包括——接收/发送缓存、拥塞控制参数、序号、确认号等。不用维持连接状态能节省一些开支,对于服务器来说尤其明显。
  • **分组首部开销小:**TCP 报文段有20字节的首部开销;UDP 仅有8字节的首部开销。

UDP 可能导致路由器中大量分组溢出,挤占 TCP 应用的流量。

可以通过应用层来保证使用 UDP 的同时实现可靠传输,就像基于 IP 协议的 TCP 协议实现了可靠传输那样。


UDP 报文段结构

UDP 首部只有4个字段,每个字段由2个字节组成。

源端口号、目的端口号、长度、校验和。

源/目的 端口号如字面意义;

**长度:**指示了在 UDP 报文段中的字节数(首部加数据);

**校验和:**检查在该报文段中是否出现了差错。

UDP 校验和

用于确定 UDP 报文段到达目的地后,其中的比特是否发生了变化。

获得校验和的方法:

以16bit为一组,进行分段、相加,舍弃最高位的进位,将结果取反,最后得到的就是校验和。

使用校验和:

还是以16bit为一组,进行分段、相加,还要再加上校验和。

如果最后得到的结果中,所有比特都为1,则表示没有错误。

为什么 UDP 协议要提供差错检测功能?

底层有可能会使用一条没有差错检测的协议,且报文段存储在路由器的内存中时也有可能会发生错误。

相对于在更高层次实现差错检测功能,在 UDP 中添加这一功能开销并不大。

UDP 没有纠错恢复的能力,对于出错的包,直接丢弃,不对发送方发出错误警告。


可靠数据传输原理(TCP前置知识)

可靠数据传输,就是指数据比特在传输过程中不会损坏、不会丢失、且所有数据都是按其发送顺序进行交付的

在讨论可靠数据传输时,可将下层协议视为不可靠的。


构造可靠数据传输协议

rdt1.0

最简单情况:底层信道完全可靠。
在这里插入图片描述

发送方:

收到调用后打包发送。

接收方:

获得包后提取提交。

只发送、接收,都没有多余的动作。


rdt2.0

考虑到发送方发送的分组可能会受损,需要额外三种机制处理比特差错的情况:

  • 差错检测:发送方在发送分组时附上校验和。需要发送额外的比特。
  • 接收方反馈:接收方在收到发送方的分组后,向发送方回复明确的反馈信息
  • 重传:发送方通过反馈获知接收方收到有差错的分组,发送方重新发送该分组。

在这里插入图片描述

发送方:

  • 发送分组时额外发送了校验码

  • 多出一个等待状态,如果收到NAK,就重传分组;如果收到了ACK,离开等待状态。

接收方:

根据发送方分组内额外的校验码,判断分组是否受损。

根据判断结果决定 接收分组、反馈ACK反馈NAK

一方额外发送了了checksum后,另一方就能调用(not)corrupt检错。

发送方仅当收到ACK,离开等待状态后,才能继续发送下一个分组。因为这种行为,rdt2.0被称为停等协议


rdt2.1

考虑到ACK或NAK分组受损的可能性。为发送方分组加上序号。

序列号在0和1之间循环,在rdt2.0的基础上双方的状态都变为2倍。

在这里插入图片描述

在这里插入图片描述

发送方:

  • 为发送分组加上了序列号。
  • 接收方反馈也有出错的可能,在收到反馈后,发送方进行校验。
  • 只有在正确收到了ACK号后才离开等待状态。

接收方:

  • 在发送反馈时也加上校验和。
  • 如果 分组未受损 且 序号正确,向上提交分组数据。
  • 当收到受损的分组时,执行的动作与rdt2.0一致。
  • 收到未受损但序号错误的分组,仍反馈ACK,但不向上提交分组数据。

自己曾有过的疑问:只有2个序号交替使用,能否保证分组顺序接收?

:没问题。发送方只有在“正确接收到ACK号”后才会进入下一个发送状态。自己试过推演,只有在接收方发送的ACK号受损时,接收方的状态会比发送方的状态快一步,其余情况二者状态基本是同步的。

接收方在收到序列号错误的分组后,仍反馈ACK号,就是为了让落后一步的发送方进入下一个状态,与接收方同步。


rdt2.2

rdt2.1的改进,移除NAK信息,在ACK中加入编号,同时达成确认、否认的效果。

在这里插入图片描述

发送方:

仅修改了判断条件,将NAK替换为ACK+(错误的序号)

接收方:

  • 接收方的ACK号加上了序列号。
  • 只要分组没受损,就发送ACK+(当前等待的序列号),通过ACK+(序列号)的组合,让发送方自行判断发送是否顺利。
  • 等待状态的2个判断条件合并为1个:接收到受损分组或错误的分组,都反馈ACK+(错误的分组序号)

帮助理解,若将其人格化,可视为:

rdt2.2之前,发送的分组是否成功是由接收方作出判断,发送方根据反馈的ANK/NAK作出简单的回应即可;

rdt2.2的接收方成了简单回应的一方,仅仅回复“我收到了序号为 0/1 的分组”。而发送的分组是否成功改为由发送方作出判断。


rdt3.0

除了所有分组都有可能比特受损外,底层信道还会丢包

在这里插入图片描述

(只有发送方的图,接收方的状态作为课后练习了)

发送方:

  • 在发送时设定一个计时器开始计时。
  • 收到发送出错的反馈,不执行任何动作;只有当计时器超时,才重发分组。
  • 收到正确的反馈后,停止计时器。
  • 在等待调用时不理睬收到的任何反馈。

相对于rdt2.2,增加了计时器。

分组序号在0和1之间交替,rdt3.0也称为比特交替协议




流水线可靠数据传输协议

rdt3.0协议能正常工作,但性能不满意,因为它是一个停等协议。

一个停等协议发送2个分组的间隔时间至少是一个RTT,因为只有收到了针对前一个分组的ACK后,下一个分组才能开始传送。

一个简单的解决方法:允许发送方发送多个分组而无需等待确认。

可以大量输送的分组看做是填充到一条流水线中,所以这种技术也被称为流水线。

流水线技术的影响:

  • 序号范围增加:仅0和1不够用了,输送中的每个分组必须有一个唯一的序号
  • 协议的发送/接收方两端必须缓存多个分组:发送方最低限度要能缓存已发送但未确认的分组;接收方要能缓存已正确接收的分组。

序号范围和缓冲的要求取决于数据传输协议如何处理丢失、损坏、延时过大的分组

流水线差错恢复的2种基本方法:退回N步、选择重传。


回退N步(GBN)

通过收到重复ACK唯一的计时器超时来判断。

GBN:Go-Back-N

允许发送方发送多个分组而不需要等待确认。分组数量受限于流水线中未确认的分组数N。

基序号 base:最早未确认分组的序号;

下一个序号 nextseqnum:最小的未使用序号,即下一个待发分组的序号。

发送方:每发送一个分组,nextseqnum++;每确认一个分组送达,base++

在这里插入图片描述

如图所示,序号范围可分为4部分:

  • 已发送并被确认的分组;(窗口外)
  • 已发送但未确认的分组;(窗口内)
  • 将要被发送的分组;(窗口内)
  • 目前无法使用的分组。从base开始的分组被确认后才能被使用。(窗口外)

随着协议的运行,序号空间表示的窗口向前滑动。所以:

N 也被称为窗口长度GBN也被称为滑动窗口协议

流量控制是对发送方施加限制的原因之一。


在这里插入图片描述

在这里插入图片描述

发送方:

1、

一开始先检查窗口是否已满(if(nextseqnum < base + N)),如果未满,产生一个分组并将其发送,更新nextseqnum(下一个要发送的包的序号);

如果窗口已满,拒绝发送;

如果窗口内没有发送但未确认的分组(base == nextseqnum),开始计时。

2、

如果超时,则重新计时,从base开始,将所有已发送、未确认的 分组重新发送。

3、

收到ACK号,更新base,如果所有发送的分组都已确认(base == nextseqnum),停止计时;否则更新计时。

接收方:

如果收到的分组未受损、序列号正确,接收并返回一个ACK,将“期待的序列号” expectedseqnum++

如果序号不正确,丢弃分组,回复最近按序正确接收的分组序号。



特点

学了TCP之后的补充:

GBN的接收方只认准了下一个期待接收的分段组,失序的分段组一律抛弃,回应之前正确接收的分段组的ACK

GBN的发送方一旦发现丢包,就得重传丢包分段组及之后的所有分段组。

GBN 协议使用的是累计确认,如果序号为k的分组已接收并交付,则序号为k-1及之前的分组也已经交付。

发送方要维护窗口的上下边界及nextseqnum

接收方只需要维护下一个按序接受的分组序号expectedseqnum

实践中,分组的序号承载在分组首部的一个固定长度的字段中。如果分组序号字段是k比特,则序号范围是[0, 2k -1],是个循环队列。


窗口大小为4的例子

在这里插入图片描述


选择重传(SR)

通过任一计时器超时来判断。

SR:Selective Repeat

当窗口长度和带宽时延都很大时,单个分组出现差错,就会使得GBN重传大量分组。

SR协议仅让发送方重传那些它怀疑丢失、受损的分组。

帮助理解:

GBN和SR的窗口都一样,可以在黑色的块中向右滑动,但会被灰色的块挡住。

GBN在窗口中从左向右严格递增填充黑色块;

SB在窗口中“随机”填充。

在这里插入图片描述

发送方:

1、从上层收到数据

行为与GBN一样,如果窗口有空余,打包发送;如果窗口已满,拒绝发送。

2、超时

与GBN不同,SR中每个分组都要有自己的计时器,因为超时发生后只重传一个分组。

3、收到ACK

收到ACK后将对应分组标记为已确认。如果ACK确认的分组序号等于send_base,则将窗口基序号send_base向前移动到最小序号的未确认分组处。(向右滑动窗口)

接收方:

1、序号在窗口内的分组

接收、缓存、返回ACK。

如果分组序号等于接收窗口的基序号rcv_base:将所有黑色块的报文交付上层,窗口向右滑动,直到被灰色块卡住。

2、序号在rcv_base之前的分组

都得返回一个ACK号,即使该分组已被缓存或提交。(为了使发送方窗口能向前滑动)

特点

学了TCP之后的补充:SR的接收方也要维护窗口,缓存失序的分段组,对每个接收的分段组都回应响应的ACK

例子

在这里插入图片描述

隐患

当窗口长度太大,接近序号的取值范围时,接收方可能无法分清一个分组是重传还是一个新分组。(因为循环队列的性质)

所以窗口长度必须小于等于序号空间大小的一半

TCP

  • 面向连接:在数据报文开始传输之前,通信双方先交换运输层控制信息,过程被称为握手

  • **可靠数据传输:**通过流量控制、序号、确认、定时器,TCP 确保正确地、按序地将数据从发送进程交付给接收进程。

  • **拥塞控制:**可以看做是提供给整个因特网的服务。避免任何一条 TCP 连接使用过多流量。

TCP在进行握手时,连接双方都要初始化与TCP连接线管的许多TCP状态变量。

TCP连接是一条逻辑连接,相关状态仅保留在两个通信的端系统的TCP程序中。

TCP提供全双工服务:双方能同时收发信息。

TCP总是点对点的,一个TCP连接中不可能有多个发送方或多个接收方。


TCP的连接过程

需要知道服务器的IP地址、服务器程序使用的端口号

经过三次握手建立连接。(细节在后文)

建立连接后,客户端进程通过套接字将要发送的数据存入发送缓存中。TCP在方便的时候,从缓存里取出数据传递给网络层。

书中提到,TCP规范没有规定发送数据的时机。

发送缓存在握手期间设置。

MSS MTU

MSS(Maximum Segment Size,最大报文段长度)

TCP报文段中应用层数据的最大长度。

MTU(Maximum Transmission Unit,最大传输单元)

MTU = MSS + TCP/IP头部信息

TCP接收到一个报文后,将报文段数据放入TCP连接的接收缓存中,应用程序通过套接字从这个缓存中读数据。



TCP报文段结构

TCP报文段 = 首部字段 + 数据字段。

当TCP发送一个大文件时,会将文件划分成长度为MSS的若干块(通常最后一块小于MSS)。

P.154的图很直观

与UDP一样的2Byte(16bit)的源端口号目的端口号

32bit的序号字段,32bit的确认号字段。这些字段被TCP连接双方用于实现可靠数据传输

4bit的首部长度字段。该字段知识了以32bit的字为单位TCP首部长度

4bit的保留字段。一般设置为0。

8bit的标志字段

CWR:在拥塞通告中使用。

ECE:同上。

URG:置1时,指示报文段中存在着被发送端上层置位“紧急”的数据,报文段之后的紧急数据指针有效。

ACK:置1时,确认字段中的值有效。

PSH:置1时,指示接收方立即将数据交给上层。

RST:置1时,表示TCP连接异常,必须强制断开。

SYN:置1时,表示希望建立连接。

FIN:置1时,指示断开连接。

16bit的接收窗口字段。该字段用于流量控制。

16bit的校验和。与UDP使用同样的方法。

16bit的紧急数据指针。只有在URG为1时有效。从数据部分的首位紧急指针所在的位置就是紧急数据。因此,紧急数据指针指向紧急数据的最后一个字节

可选与边长的选项字段。用于TCP连接双方协商MSSC长度,或在高速网络环境下用作窗口调节因子。


序号和确认号

TCP报文首部最重要的2个字段是序号字段确认号字段


序号

TCP把数据看成一个无结构的、有序的字节流,TCP的序号就是建立在传送的字节流上。一个报文段的序号就是该报文段首字节的字节流编号(首字节应该是指MSS的首字节)。

TCP将隐式地对数据流中的每个字节编号。(的确是每个字节)

假设:有一个数据流由50,000字节的文件组成,MSS为1000字节。数据流的首字节编号是0。

TCP将会为该数据流构建50个报文段:第一个报文段分配序号0;第二个分配序号1000;第三个分配序号2000……

0 ~ 999,刚好1000个字节,下一个字节(第1001个字节)编号就是1000。

每个序号填入报文段首部的序号字段中。

实际应用中,初始序号是随机的。这能避免将那些仍游荡在网络中的、双方主机之前已终止的连接的报文段,认作后来双方主机之间新建立的连接所产生的有效报文段

用大白话解释:2台主机使用端口x建立了一个TCP连接α,完成任务后断开。之后很快通过同一个端口x又建立了TCP连接β,如果初始序号固定,就有可能将前一次连接α发送的报文段,认为是连接β发送的报文段,导致通信出错。



确认号

假设2台主机A、B使用TCP相互通信,

主机A回应主机B的确认号是主机A期望从主机B收到的下一个字节的序号

假设:主机A已经收到了来自主机B的编号为 0 ~ 535 的所有字节,则主机A就会在发往主机B的报文段中的确认号字段填上536。

累计确认

假设:主机A收到了来自主机B的包含字节0 ~ 535 和 900 ~ 1000 的报文段,因为未知原因,还未收到包含字节 536 ~ 899 的报文段。

在这个例子中,主机A在回应主机B发来的报文段时,一直将536填入确认号字段。

因为 TCP 只确认数据流中第一个未确认的字节。(丢失或未收到导致未确认)

换句话说,接收方发回了ACK号,该ACK标识的字节之前的数据一定都按序接受了。

例如:序号从0开始,收到ACK=x,那么0 ~ x-1这段数据一定都按序发送到了。

**上述例子引出的问题:**如果报文段失序到达,先接收到了 900 ~ 1000 的报文段,再接收到 536 ~ 899 的报文段,该如何处理?

之前不是提到了滑动窗口吗,直接将接收方的窗口向右滑动,直到遇到新的未确认的序号。

RFC没有做出规定,由实现TCP的编程人员处理。

解决方法一

收到失序的报文段后直接抛弃。简化设计。

解决方法二

保留失序的报文段,等待空缺被填上。这一方法对网络宽带更有效,且是实践采用的方法。


序号字段和确认号字段始终都要填入TCP报文段中,该报文段无论是否带有数据。

捎带

在发送报文段数据的同时顺带发送序号确认号


往返时间的估计与超时

具体公式细节:P.158。

概念

SampleRTT(样本RTT):某个报文段从发出(交给IP)到收到回应时经过的时间。

大多数TCP的实现仅在某个时刻,测量一次SampleRTT。另外,TCP绝不为被重传的报文段计算SampleRTT。

TCP绝不为被重传的报文段计算SampleRTT原因被书作为课后练习。

自己的想法:因为TCP重传的报文段并不一定是被确认丢失的报文段,可能因为网络阻塞等原因,使得对方的回应报文段回应较慢。所以可能会出现:重传的报文段刚刚发出,就立即收到该报文段的回应的情况。以这个RTT作为SampleRTT明显是没有参考意义的。

EstimatedRTT(SampleRTT均值):SampleRTT会受网络波动影响,任何SampleRTT都是非典型的,所以需要维持一个均值,作为超时重传的参考。

EstimatedRTT = (1 - a) * EstimatedRTT + a * SampleRTT

a为权值,推荐值是0.125。

DevRTT(RTT的变化):用于估算SampleRTT偏离EstimatedRTT的程度。

DevRTT = (1 - b) * DevRTT + b * abs(SampleRTT - EstimatedRTT)

b的推荐值为0.25。

超时时间设置太长,会使TCP不能很快重传报文段,导致数据传输时延大;设置得太短,会阻塞网络。

超时时间的设置应该大于EstimatedRTT,多出的余量参考DevRTT,波动大余量大,反之余量小。

TimeoutInterval = EstimatedRTT + 4 * DevRTT

可靠数据传输(补充)

之前的讨论中,假定每个已发送单位确认的报文段都与一个定时器相关联。但实际上,定时器的管理需要大量开销,所以RFC推荐的定时器管理仅使用单一的重传定时器

TCP发送方的简化描述:

NextSeqNum = InitialSeqNumber
SendBase = InitialSeqNumber

while(1)
{
    switch(事件)
        事件1: 从应用层程序接收到数据data
            生成具有序号NextSeqNum的TCP报文段
            if(定时器未启动)
                启动定时器
            向IP协议传递报文段
            NextSeqNum += length(data)
            break;
        
        事件2: 定时器超时
            重传具有最小序号但未应答的报文段
            启动定时器
            break;
        
        事件3: 收到ACK,具有ACK字段值y
            if(y > SendBase)
            {
                SendBase = y
                if(当前仍无任何应答报文段)
                    启动定时器
            }
            break;
}

事件3:SendBase是最早未被确认的字节的序号,SendBase-1就是接收方已正确按序接收到的数据的最后一个字节的序号。

如果当前还有未被确认的报文段,TCP还要重启定时器。

一些特殊情况的处理
ACK号丢失

情况:主机A主机B发送报文段,主机B正确接收,但回应的ACK号没到达主机A

处理:主机A重传报文段,主机B收到重传报文段,通过序号发现该报文段的数据早已收到,所以抛弃该报文段,仍回复之前的ACK号。

!连传2个报文段,ACK号丢失(单个计数器的运作)

情况:主机A主机B连发2个报文段,主机B正确接收,但回应的ACK号没到达主机A

处理:

主机A重传第1个报文段,重启定时器。只要第2个报文段的ACK号新的超时发生前到达主机A,第2个报文段就不会重传。

主机B只发送第2个报文段的ACK确认报文(累计确认)。

连传2个报文段,仅第1个报文段的ACK丢失

只要在超时发生前,主机A收到第2个报文段的ACK报文,则2个报文段都不用重传。

超时间隔加倍

超时事件发生时,TCP重传具有最小序号的、还未确认的报文段。且每次重传都会将下次的超时间隔设置为先前的2倍,而不是使用计算出来的TimeoutInterval

当定时器启动是由另外2个事件(上层调用、收到ACK)触发时,使用TimeoutInterval

快速重传

超时间隔加倍的处理会导致发送方延迟重传丢失的分组,从而增加了端到端的时延

发送方可在超时事件发生之前,通过冗余ACK检测丢包情况

快速重传就是检测到丢包后,不等超时事件发生,立即重传丢失的报文段。

冗余ACK哪来的?:

TCP接收方收到了一个报文段,该报文段的序号大于接收方所期望的、按序的报文段,接收方检测到了数据流中的一个间隔,也就是报文段丢失。

因为TCP不使用否定确认,所以接收方会对已经接收到的最后一个按序字节数据进行重复确认。这就是冗余ACK。(同时接收方会保存该失序报文段)


TCP接收方回应ACK的动作

原表P.163,这里记自己的理解

事件TCP接收方动作
收到按序到达的报文段延迟的ACK。等待一段时间再发送ACK,等待不超过500ms
延迟的ACK期间又收到按序报文段立即发送单个累积ACK
比期望序号大的失序报文段立即发送冗余ACK
收到的报文段能部分或完全填充接收数据间隔如果该报文段起始于间隔的低段,立即发送ACK

发送方收到了3个冗余ACK后,知道这个已被确认3次的报文段后面的报文段丢失。执行快速重传

为什么是3个冗余ACK,而不是1或2或4个?

https://datatracker.ietf.org/doc/html/rfc2001#section-3

RFC文档中表示:“It is assumed that if there is just a reordering of the segments, there will be only one or two duplicate ACKs before the reordered segment is processed, which will then generate a new ACK.

“If three or more duplicate ACKs are received in a row, it is a strong indication that a segment has been lost.”

大致意思就是,1或2的冗余ACK很可能是乱序导致的结果,不需要重传。文档中没有进行论证。

而不是4或更多的冗余ACK的原因:使用快速重传就是为了避免慢启动(超时间隔加倍),所以选择3是能达成较低的通信时延。

引入了快速重传机制后的代码描述:

        事件3: 收到ACK,具有ACK字段值y
            if(y > SendBase)
            {
                SendBase = y
                if(当前仍无任何应答报文段)
                    启动定时器
            }
            else
            {
            	ACK字段值为y的冗余ACK数+1
            	if(ACK字段值为y的冗余ACK数 == 3)
            		TCP快速重传,重新发送具有序号y的报文段
            }
            break;
TCP的重传机制

书中最后的结论:TCP的重传机制也许最好被分类为GBN协议和SR协议的混合体。

* Is TCP like GBN or SR? TCP does something in between GBN and SR, closer to SR. TCP sends only one packet that it thinks is lost, not entire window, so not like GBN. 
TCP receiver buffers out of order segments. But ACK indicates the sequence number that is missing (unlike SR). 
TCP selective ACK (SACK) option exists to ACK a few out of order segments also. But the main ACK sequence number in TCP header is used to inidcate the first packet that is expected next. TCP with SACK is a lot like SR. 

比较:

TCP协议只有1个定时器,像GBN;

TCP协议中的接收方只会发送最后一个按序接受的分段组的确认报文段,像GBN;(SR也会回应失序的分段组ACK,接收方通过每个分段组都有的计时器,确认超时分段组,进行重传)

TCP协议只会重传它认为丢失的分段组,像SR;

TCP协议接收方会缓存乱序到达的分段组,像SR。

补充“TCP协议只会重传它认为丢失的分段组”

假设报文段n会导致超时,TCP只会重传报文段n

如果在超时之前发送方收到了报文段n+1或之后的确认报文,TCP甚至不会重传报文段n。因为对于接收方来说,它一定是按序收到了报文段n+1及之前的所有报文段。

流量控制(接收窗口)

TCP连接的接收方可能不会立即从缓冲区中读取数据,所以要通过流量控制防止发送方发出太多的数据报导致接收缓存溢出。

流量控制因此是一个速度匹配服务,使双方的发送速率、接收速率相匹配。

TCP发送方的发送速率因网络拥塞而被抑制,这种形式的控制称为拥塞控制,虽然与流量控制采取的措施相似,但二者是针对完全不同的原因而采取的措施。


具体措施

TCP让发送方维护一个接收窗口,该窗口用于提示:对方的缓冲区还有多少空间可用

假设主机A主机B发送一个大文件,主机B为该连接分配了一个大小为RcvBuffer的接收缓存。

变量定义:

主机B

LastByteRcvd——从网络中到达并放入主机B接收缓存中的数据流的最后一个字节编号;

LastByteRead——主机B上的应用进程从缓存读出的数据流的最后一个字节编号;

rwnd——主机B缓冲区的空闲空间。

rwnd = RcvBuffer - (LastByteRcvd - LastByteRead)

主机A

LastByteSend——主机A发送到连接,但未确认的数据流的最后一个字节号;

LastByteAcked——主机A收到回应的字节流的最后一个字节号。

主机A在该链接的整个生命周期中必须保证:

LastByteSend - LastByteAcked <= rwnd

主机B通过把当前的rwnd值放入它发给主机A的回应报文段中,通知对方自己的缓冲区还有多少剩余空间。


缺陷

假设接收方缓冲区已满,rwnd=0,不久后接收方的应用程序从缓冲区中取走数据。因为接收方仅当收到发送方的报文段后,才会发送回应报文段,这使得发送方无法得知接收方的窗口状态,发送被阻塞。

解决

为此,TCP规定:当接收方的窗口为0时,发送方继续发送只有一个字节数据的报文段。这个报文段会被接收方确认,

https://www.brianstorti.com/tcp-flow-control/

当接收窗口为0时,发送方启动一个称为Zero Window Probes (ZWPs)的计时器,不断向接收方发送一个报文段,直到接收方窗口腾出空间。

三次握手细节

第一次 SYN

发送方---(SYN = 1, seq = client_isn)--->接收方

客户端发送一个SYN报文段,报文段的SYN标志位置位1,表示建立连接;同时发送随机选择的初始序号client_isn

随机选择初始序号是为了避免受到攻击。

第二次 SYN + ACK

发送方<---(SYN = 1, seq = server_isn, ACK = client_isn + 1)---接收方

服务端同样以SYN报文段回应,SYN=1、发送服务端的初始序号server_isn、确认字段ACK=client_isn+1

如果在这阶段,服务端开始为TCP连接分配缓存和变量,会使得服务器易受SYN洪泛拒绝服务攻击

第三次 ACK

发送方---(SYN = 0, seq = client_isn + 1, ACK = server_isn + 1)--->接收方

收到SYNACK报文段后,客户端为TCP连接分配缓存和变量。

因为连接已经建立了,SYN=0seqACK就像普通的TCP报文段那样填写。

实际上,第三次握手的报文段,除了数据区没有数据外,基本上与普通的报文段没有区别了。(自己的想法)

客户端收到SYN+ACK后进入ESTABLISHED状态;

服务端收到ACK后进入ESTABLISHED状态。

为什么是3次握手?

观点一:

谢希仁《计算机网络》:是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。

例子:客户端第1次握手的报文因为网络阻塞超时,在重发达成了2次握手后,之前的第1次握手报文段姗姗来迟,而服务端将其认为是客户端又发起了一个TCP连接请求。

如果使用的是2次握手,则服务端以为建立了2个TCP连接并为其分配资源,而客户端只认为建立了1个TCP连接。这就浪费了服务端的资源。

观点二:

TCP的报文都有一个发送数据、收到确认的成对的流程,至于收到确认,是不需要对确认进行确认。所以根据这种思路,可以将3次握手看成以下形式:

第1次握手:数据(SYN、seq)

第2次握手:确认(ACK)+数据(SYN、seq)

第3次握手:确认(ACK)

如果2次握手就能建立连接,则服务端无法获知客户端是否已收到自己的seq序列信息,所以3次握手是为了让客户端必须给服务端一个回应。

第2次握手就是将服务端的确认服务端的数据2个报文段合并为1个报文段。

握手过程的丢包

哪一方发出报文段后未收到ACK,哪一方就重发。

第2次握手的SYN+ACK同时有数据和ACK的属性,网上的搜索中,大家都不关心SYN+ACK报文段的丢失,似乎都默认SYN+ACK报文段丢失是由客户端重新发送。

如果第3次握手的ACK报文段丢失,客户端认为连接已建立,而服务端会多次重发SYN+ACK报文段,直到收到ACK进入ESTABLISHED状态,或重复次数太多,发送RST报文段放弃连接。

在重发SYN+ACK报文段的过程中如果收到客户端发来的数据,似乎会以RST报文段回应。

一些面试问题

问:如果已经建立了连接,但是客户端突然出现故障了怎么办?

答:TCP设有一个保活计时器,服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,计时器超时后,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,关闭连接。

断开连接(四次挥手)

书中进没有详细展开。

TCP连接两端的任何一方都能终止连接(图中是客户端主动关闭连接)。

在这里插入图片描述

一些面试问题

问:为什么是4次挥手?

每个TCP数据报文段都要有一个ACK报文段回应,客户端发出FIN报文段后,服务端必须有一个ACK报文段回应;

在客户端申请关闭连接时,服务端可能还有数据在发送中,无法立即关闭连接,所以不能像建立TCP连接时那样,将FIN位与ACK同时发送。只有在服务端完成了收尾工作后,才发送FIN报文段,通知客户端自己准备断开连接。

问:为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

MSL(Maximum Segment Lifetime)报文最长存活时间

TCP的下层协议是不可靠的IP协议,最后一个ACK报文段有可能会丢失,TIME_WAIT状态是让客户端在等待可能因为ACK丢包而重发的FIN报文段。

2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,就判断ACK已经被成功接收,结束TCP连接。

客户/服务TCP经历的TCP状态序列

(这些状态在linux中可以通过netstat指令查阅到)

具体的图片在书中P.168~P.169。

SYN洪泛攻击和防御

SYN洪泛攻击

TCP连接建立时,服务器响应收到的SYN报文段后,分配并初始化相关的链接资源,并发送SYNACK报文段进行回应。如果客户端没有回复ACK报文段,则服务器在等待一段时间后(1分钟左右)终止半开连接,回收资源。

攻击者利用这段间隔发送大量的TCP SYN报文段,而不完成第三次握手,使得服务器分配了大量不会被使用的资源,导致资源耗尽宕机。

SYN cookie

SYN cookie是防御SYN泛洪攻击的一种手段,现已被大多数的操纵系统集成。

其防御的思路采用了hash值不可逆的原理,在接收到客户端发送的SYN后,服务器不会为该报文段生成半开连接。用源ip目标ip端口号、只有该服务器知道的秘密数,四个值一起计算得到一个hash值cookie,用cookie作为序列号返回SYNACK,重要的是,服务器不会记录cookie或任何与SYN相关的其他状态信息。

当有客户端ACK返回时,使用源ip目标ip端口号秘密数再次计算cookie,如果得到的cookie+1 == ACK号,就认为它是合法的,生成全开连接,否则丢弃。

拥塞控制原理

原因和代价

P.171

模型一:2个发送方使用一条链路通信,中间有一个无穷大缓存的路由器。R为共享链路的容量。

结论:2个主机的最高发送速率是R/2,且发送速率越接近R/2,分组的时延越大。

吞吐量与发送速率的关系是一元函数y=x

P.173

模型二:2个发送方使用一条链路通信,中间的路由器缓存容量有限。R为共享链路的容量。

结论:分了3种情况,具体看书。有用的信息:发送方在遇到大时延进行的不必要重传会进一步加剧阻塞状况。

P.173

模型三:4个发送方使用有限缓存的多台路由器多跳路径

结论:更麻烦了。有用的信息:由于拥塞而丢弃的分组的另一种代价,当一个分组沿一条路径最终被丢弃时,之前经过的路由器转发该分组的操作就都是无意义的了。

拥塞控制方法

根据网络层是否为运输层的拥塞控制提供了显式帮助来区别:

  • 端到端拥塞控制:网络层没有为运输层拥塞控制提供显式支持。TCP使用了这种方式。
  • 网络辅助的拥塞控制:路由器向发送方提供关于网络中拥塞状态的显式反馈信息。反馈信息可以用一个比特来指示链路的拥塞情况。IP和TCP能选择性地实现网络辅助拥塞控制。

网络辅助的拥塞控制有2种方式:

1、直接反馈信息 :由路由器发给发送方一个阻塞分组。

2、经由接收方的网络反馈:更通用,路由器标记或更新发送方发往接收方的分组中的某个字段来指示拥塞的产生。再由接收方向发送方通知网络拥塞指示。

TCP拥塞控制

TCP采用端到端拥塞控制

所采用的方法是:让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。如果没感觉到拥塞,提升发送速率;否则降低发送速率。

引出的问题:

1、如何限制发送速率?

2、如何如何感知到拥塞?

3、感知到拥塞后,如何改变发送速率?

限制发送速率

发送方跟踪一个额外的变量:拥塞窗口cwnd。与rwnd不同,rwnd是由接收方跟踪,在发送ACK报文段时一起通知给发送方的。

补充:发送方自己也有个发送窗口swndswnd = LastByteSend - LastByteAcked,所以swnd <= min{cwnd, rwnd}

通过cwnd约束发送方的发送速率。

下文讨论cwnd细节。

感知拥塞

TCP发送方的丢包事件定义为:要么超时,要么收到来自接收方的3个冗余ACK。发生这些事件就意味着发生了拥塞。

确定发送速率

指导性原则:

  • 丢失报文段意味着拥塞,降低TCP发送方速率。
  • 未确认报文段的确认到达,意味着无拥塞,增加TCP发送方速率。
  • 带宽探测。ACK正确到达就提升速率,一发现丢包就降低速率。反复试探。

网络中没有明确的拥塞状态信息,ACK和丢包事件充当了隐式信号。

了解了TCP拥塞控制后,就能开始讨论TCP拥塞控制算法的细节了。

算法主要包括3个主要部分:1.慢启动;2.拥塞避免;3.快速恢复。

慢启动拥塞避免是TCP的强制部分,快速恢复是推荐部分。

慢启动

TCP连接开始时,cwnd初始化为一个MSS的较小值,使得初始发送速率大约为MSS/RTT。

在慢启动状态,每收到一个ACK就将cwnd的长度增加一个MSS,使得cwnd的增长速率是2k,k为发送方的发送次数。

论证:刚开始发送1个MSS,收到1个ACK,增加1个MSS(已有2个);第2次发送,发送2个MSS,收到2个ACK,增加2个MSS(已有4个)……这就使得每过一个RTT,发送速率就翻倍。

指数增长的终止:(变量ssthresh初始化为64KB,P.179)

1、发生超时丢包事件cwnd被设置为1 MSS重新开始慢启动过程,并将变量ssthresh设置为cwnd/2(重置之前的值)。重新发送丢失的报文段。

2、与变量ssthresh相关,当cwnd >= ssthresh时,继续翻倍cwnd可能又会导致丢包,所以结束慢启动模式切换到拥塞避免模式

3、检测到3个冗余ACK,TCP进入快速恢复状态执行快速重传。重新发送丢失的报文段。ssthresh = cwnd/2, cwnd = ssthresh+3*MSS

拥塞避免

进入拥塞避免状态,cwnd的值大约是上次遇到拥塞时的值的一半,并且离再次拥塞的距离不远。所以TCP采用保守的方法,每个RTT只将cwnd的值增加一个MSS

(例如,当前的cwnd是10个MSS大小,则每收到一个ACK就将cwnd的值增加1/10个MSS,10个ACK后刚好一个MSS)

拥塞避免的线性增长的结束:

1、超时事件。处理方式与慢启动一样,cwnd重置为1 MSS,ssthresh = cwnd/2,然后切换到慢启动状态。重新发送丢失的报文段。

2、检测到3个冗余ACK,TCP进入快速恢复状态执行快速重传。重新发送丢失的报文段。ssthresh = cwnd/2, cwnd = ssthresh+3*MSS

快速恢复

3种情况:

**1、收到冗余ACK。**对于每个冗余ACK,cwnd的值增加一个MSS。

2、收到丢失报文段的ACK(没问题的ACK)。降低cwnd的值(cwnd = ssthresh ),进入拥塞避免状态。

**3、超时。**处理方法与前2者一致。设置完变量后,切换到慢启动状态。重新发送丢失的报文段。

看P.179的图描述,快速恢复阶段如果收到重复ACK,处理方式与其它2种状态收到正确ACK的处理方式相同:增加cwnd并发送新的报文段。

why?

公平性

假设有K条TCP连接都经过一段传输速率为R的瓶颈链路,如果每条连接的平均传输速率接近R/K,则认为该拥塞控制机制是公平的。

P.183的图看一下就行了。

TCP拥塞控制会限制传输速率,所以因特网点火和视频会议会使用UDP协议。

UDP协议不在乎拥塞情况,所以UDP的数据可能会压制TCP流量。

并没有什么有意义的知识点。

明确拥塞通告(了解即可)

对于IP和TCP的扩展方案已提出并实现和部署明确拥塞指示。

明确拥塞通告(Explicit Congestion Notification,ECN)。

在网络层,IP数据报首部的服务类型字段中的2个比特被用于ECN。路由器用它来指示该路由器正在经历拥塞,被标记的IP数据报传到TCP连接的接收方后,再由接收方通知发送方。

路由拥塞的判断由厂商做配置选择,由网络操作员决定。

IP

IP 的服务模型是尽力而为交付服务(best-effort delivery service),可靠信、顺序交付、完整性等等都不考虑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值