1、应用层
重点协议:HTTP
1.1 应用层协议原理
1.1.1 应用程序体系(宏观来看):
- 客户服务器体系结构
一台中央主机来服务与所有的客户点的请求(为了防止跟不上客户请求,可能不止一个,构成了数据中心) - P2P体系结构
特点:自扩展性
每一个客户都可以变成主机,各个应用程序之间直接通信,不需要主机进行转换发送,这些主机称为“对等方”。
1.1.2 进程通信(多个端系统之间如何相互通信?)
- 客户与服务器定义
如P2P来说,一个进程既可以是客户,也可以是服务器 - 进程与计算机网络之间的接口
进程必须通过网络来传递信息,那么进程通过“套接字(socket)”的接口来对网络发送和接收报文信息(从应用程到运输层)。套接字又被称为应用程序与网络之间接口(API)。 - 进程寻址
向目的地发送信息需要一个地址(IP),目的地接收信息同样也需要一个地址,分为两部分IP地址+端口号(COM)。用于在网络中找到对方主机(IP)和定义应用进程(COM)
1.1.3 应用程序可以使用的运输服务(应用层所使用的运输服务)
上文提到API,将报文通过API传递给运输层,运输层同时也提供相关的运输服务给报文,这里应用程序一共可以使用以下几种报文:
- 可靠数据传输
运输层确保一端发送的数据正确、完全的交付到另一端中。
分为两种:容忍丢失的应用(丧失准确性提升实时性,如网络电话)与无法容忍的应用(电子邮件、文件传输) - 吞吐量
可用吞吐量:发送进程能够向接收进程交付比特的速率
带宽敏感应用是对吞吐量敏感的应用,弹性应用则可以根据当时可用的带宽或多或少的利用可供使用的吞吐量。
(吞吐量越多越好) - 定时
定时保证(不太重要) - 安全性
为应用程序提供加密和解密的服务(加密报文即可,端与端之间确保相关协议。)
1.1.4 因特网提供的运输服务
- TCP服务
面向连接的服务
可靠的数据传送服务
拥塞控制...etc. - UDP服务
UDP是无连接的,所以两个进程通信之前没有握手过程
没有拥塞控制机制 - 因特网运输协议所不提供的服务
(不做要求)
1.1.5 应用层协议
定义了以下内容:
- 交换的报文类型
- 各种报文类型的语法
- 字段的语义
- 确定一个进程何时以及如何发送报文,对报文进行响应的规则
1.2 Web与HTTP
web是一个互联网应用,HTTP是一个协议。
web的应用层协议为超文本协议(HTTP),是由“对象”组成的,一个对象只是一个文件,且可以通过URL寻址。每个HTML文件通过定义URL文件调用其他元素。
URL文件分为主机名和路径名,后面章节会介绍。
1.2.1 HTTP概况
Web浏览器生成了HTTP的客户端,Web服务器实现了HTTP的服务器端
HTTP主要定义了Web客户向Web服务器(不同于P2P,类似于客户服务器的形式,有一个主机来响应请求)请求Web页面的方式。HTTP运行在TCP上,而不是UDP,若HTTP建立成功,则可通过API访问TCP。
HTTP不保存任何客户信息,是一个无状态协议
1.2.2 非持续连接和持续连接(HTTP的链接类型)
相当于一条路只通一辆车和一条路通很多辆车的区别
非持续连接每个请求都是经过每一个单独的TCP连接发送,持续连接则是所有请求都通过相同的TCP连接发送。
默认情况下HTTP是持续连接
(1)非持续连接HTTP
非持续链接流程如下
# 客户端请求服务器传输一个Web界面,Web界面包含一个HTML基本文件和10个JPEG图形(位于同一服务器)
# 假如HTML文件的URL为https://www.jianshu.com/notebooks/home.index
(1)HTTP客户端从串口“80”发送了一个到服务器“www.jianshu.com”的TCP连接,“80”是HTTP的默认端口号,
客户和服务器都有一个API和该连接相关联
(2)连接建立起之后,HTTP客户通过API向服务器发送一个HTTP请求报文,
请求报文中包含请求路径/notebooks/home.index
(3)HTTP服务器经过API接收该报文(实际上就是TCP来负责传输的)
从服务器的存储器中找到该地址文件www.jianshu.com/notebooks/home.index
并封装对象,通过HTTP服务器响应报文发送出去(也是通过套接字API,TCP发送)
(4)**HTTP服务器**通知TCP断开TCP连接(准确来说是直到TCP确认客户已经完整接收到文件才会断开)
(5)HTTP客户接收响应报文,TCP连接关闭了,报文封装对象是一个HTML文件,
通过检查文件得到10个JEPG文件的引用,之后对这十个引用重复前面四个步骤。
RTT(往返时间)定义:一个短分组从客户到服务器然后再返回客户所花费的时间
所以总的响应时间就是两个RTT加上服务器传输文件的时间(TCP传输前两次握手耗费一个RTT,最后一次握手属于传输数据阶段,所以TCP三次握手耗费一个RTT+数据传输的时间)
非持续链接缺点:
- 必须每次为一个请求对象建立和维护一个新的TCP连接,Web负担严重
- 每个对象需要经过两倍的RTT时延(一个RTT创建TCP,一个RTT用于请求和接收对象)
(2)持续连接HTTP
一个完整的Web页面,只需要一个单独的TCP连接即可。不需要对每个对象重复发送,这样的话当一定时间内TCP连接没有进行数据传输的时候就关闭TCP连接。
1.2.3 HTTP报文格式
(1)请求报文
GET /somedir/page.html HTTP/1.1
Host:www.someschool.edu
Connection:close
User-agent:Mozilla/4.0
Accept-language:fr
HTTP请求报文的第一行叫做请求行(request line)
其后继的行叫做首部行,请求行有三个字段:方法字段,URL字段和HTTP协议版本字段。方法字段可以取值GET,POST,HEAD,PUT和DELETE。绝大部分的HTTP请求报文使用GET方法,当浏览器请求一个对象时,使用GET方法,在URL字段填写该对象的URL地址。该例子中为/somedir/page.html ,紧随其后的为版本字段。
再看看本例的首部行Host:www.someschool.edu,定义了目标所在的主机(该首部行所提供的信息时web高速缓存所要求的)。
Connnection:close首部行,浏览器告诉服务器不希望使用持久连接,要求服务器在发送完请求对象后就关闭连接。
user-agent:首部行用来定义用户代理,即向服务器发送请求的浏览器类型。这里的浏览器类型时Mozilla/4.0,即Netscape浏览器(与ie浏览器是竞争对手)。
Accept-language:fr 表示用户想要用该对象的法语版本。
在首部行后有一个实体主体,使用GET方法是主体为空,而使用POST方法时,实体主体包含就是用户在表单字段输入的值。
HEAD方法类似于GET方法,当服务器收到使用HEAD方法的请求时,会用一个HTTP报文进行响应,但并不返回请求对象,通常用于故障跟踪。
DELETE方法用于删除web服务器上的对象。
(2)响应报文
HTTP/1.1 200 OK
Connection:close
Date:Thu,03 Jul 2003 12:00:15 GMT
Server: Apache/1.3.0(Unix)
Last-Modified: sun, 6 May 2007 09:23:24 GMT
Content-Length:6821
Content-Type:text/html
一个是初始状态行,6个首部行,然后是实体主体。实体主体部分是报文的主体,即包含了所请求的对象本身。状态行有3个字段,协议版本,状态码和相应状态信息。
服务器用Connection:close首部行告诉客户机报文发送完毕后关闭TCP连接,
Date:首部行指示服务器产生并发送该响应报文的日期和时间。
值得一提的是,这个时间不是指对象创建或最后修改的时间
Server:首部行表明该报文是由Apache web服务器所产生的,类似于HTTP请求报文中的User-agent
Last-Modified:首部行指示了对象创建或者最后修改的日期和时间。
content-length:首部行表明了被发送对象的字节数。
content-Type:首部行指示了实体主体的对象是HTML文本。
响应报文的状态:
- 200 Ok:请求成功,信息包含在返回的报文中
- 301 Moved permanently:请求的对象已经被永久转移了,新的URL定义在响应报文的Location
- 400 Bad Request:一个通常差错代码,指请求不能被服务器理解。
- 404 Not Found: 被请求的文档不在服务器上。
- 505 Http version Not Supported:服务器不支持请求的报文使用的HTTP协议版本。
1.2.4 Cookie
用处就是帮助Web站点识别用户,允许站点对用户进行跟踪
1.2.5 Web缓存(大部分是高速缓存)
存在一个Web缓存器,将每次的HTTP请求都储存在缓存器里,并且让客户到缓存器的连接使用高速连接,可以大大节省时间。如果遇到缓存器中没有的遇到过的请求,缓存器就向原始目标地址发送HTTP请求,等HTTP响应回来之后就存储在缓存器中,并发送给客户端。
可从整体上大大减少响应时间、大大减少一个机构接入链路到因特网的通信量,还可以大大减少因特网上的Web流量,改善所有应用的性能。
1.2.6 条件GET方法
此方法允许高速缓存器证实他的对象是最新的
条件GET方法
如果HTTP发送到高速缓存中的请求报文使用GET方法,并且请求报文中首部行包含“If-Modified-Since”,则这个HTTP请求报文就是一个条件GET报文
首先,代理缓存器向服务器发送一个请求浏览器的报文
接着,服务器就会将该响应报文连同请求内容一起发送给缓存器,缓存器转化给请求浏览器后,在缓存器中储存下来该报文
一周后...
此时用户通过缓存器请求同一对象,这个对象还在缓存器之中,因为Web服务器中的对象有可能已经被修改了,所以缓存器向服务器发送一个请求,If-Modified-Since意思就是如果在这个时间点(缓存器存储的最后访问时间点)之后还没被修改的话,不需要重新发送对象,只需要发送一个未被修改的响应报文即可。如果Web服务器上的内容已经未被改变,则发送一个包含最新请求对象的报文,缓存器更新自己的存储后转发给用户
1.3 因特网中的电子邮件(未看!)
1.4 DNS:因特网的目录服务
识别主机有两种方式,分别为主机名(such as www.jianshu.com),IP地址名,最为常用的是IP地址。
1.4.1 DNS提供的服务
人们喜欢记忆主机名,路由器喜欢IP地址,所以DNS(域名系统 Domain Name System)就出现了,通过主机名称转换成为IP地址。
DNS的主要内容(数据库+应用层协议):
- 一个由分层的DNS服务器实现的分布式数据库
- 一个使得主机能够查询分布式数据库的应用层协议。
DNS服务器运行在BIND的UNIX机器上,但是协议运行在UDP上,53号端口(HTTP运行在80端口)
DNS大致工作流程:
- 客户A主机上运行浏览器(HTTP客户端)和DNS客户端
- HTTP客户端需要得到URL主机地址的IP地址来建立TCP连接,首先解包URL中主机地址,发送给DNS客户端,DNS客户端将其转发给DNS服务器,得到DNS服务器中反馈回来的IP地址,将IP地址发回给HTTP客户端,后HTTP客户端和位于IP地址的主机端口80的HTTP服务端建立TCP连接,开始传输报文。
DNS重要服务:
- 主机别名:反正就是一个不规范的主机名称,Application可以调用DNS获得主机别名对应的规范名称
- 邮件服务器别名:和上面没什么区别
- 负载分配:对于大的站点(.com/.cn等等),服务器一般都假设在很多端系统上,这些端系统都拥有不同的IP地址,所以DNS可以将所有访问这些相同站点的请求分配到这些IP地址之中
1.4.2 DNS工作机理
若DNS采取集中式,则会产生单点故障后整个系统崩溃、通信容量不足、时延严重、维护困难的缺点。所以DNS采取的是分布式设计方案。
- 分布式、层次数据库
类似一个数,分为根DNS服务器、顶级域DNS服务器、权威域DNS服务器。
这样客户首先与根节点(根DNS服务器)联系根服务器联系他的子节点服务器地址,顶级域联系权威域,权威域又找到最终的结果。
最基本的叫做本地DNS服务器,用于小范围ISP(居民区或者机构),本地DNS服务器与主机相隔一般不超过几个服务器。
DNS查询分为两种迭代查询、递归查询
迭代查询的意思就是每次都是由一个本地服务器发出查找请求,相当于叶节点不断访问他的父节点,访问他的父节点的父节点...
递归查询就是按照树的路径,一个节点一个节点的网上递归,最后返回来需要查找的地址。 - DNS缓存
就是每次查询都保存在DNS缓存中,节省查询时间,除了少数DNS查询,基本不会查询到DNS服务器
1.4.3 DNS记录与报文(未看)
1.5 P2P文件分发(应用,未看)
1.6 视频流与内容分发网(应用,未看)
2、运输层
位于应用层和网络层中间位置,主要关注TCP和UDP协议
2.1 运输层服务
运输层为不同主机上的应用提供了逻辑服务的功能
运输层并不是在路由器中实现的,而是在端系统中实现的
应用层发送报文给运输层,运输层加上运输层首部等等变成运输层报文发给网络层,网络层才负责封装成数据报并向目的地发送(运输层只连接,网络层只负责发送和传输相关数据)
2.1.1 运输层和网络层的关系
网络层是在主机之间实现了逻辑通信
运输层则是在主机应用之间实现逻辑通信
运输层协议工作在端系统中,他将端系统中来自应用系统的报文移动到网络边缘(网络层)
运输层能提供的服务往往受限于底层网络层协议的服务模型(也就是说如果网络层不能给主机之间发送的运输层报文段提供时延或者带宽保证,运输层是不能为进程之间发送的应用程序报文提供时延或者带宽保证)
运输层也可以做相关工作,比如若底层网络层不能保证运输层报文段的机密性,运输协议能使用加密来确保应用程序报文不被入侵。
2.1.2 因特网运输层概述
运输层分组称为报文段(segment),有些文章中将TCP称为报文段,UDP称为数据报
IP的服务模型属于尽力而为交付服务,他付出自己最大的努力来传输数据,却不保证数据是否完整、有序的传输的,是不靠谱的服务。
运输层两大协议最主要的交付服务称为多路复用和多路分解(后文有介绍)
TCP提供可靠数据传输服务,并且提供拥塞控制功能,这都是UDP做不到的
2.2 多路复用和多路分解
含义:将由网络层提供的主机到主机的交付服务延伸到为运行在主机上的应用程序提供进程到进程的交付服务
多路分解:将服务端收到的报文段的数据交付到正确的套接字的工作
多路复用:将客户端不同套接字上收集数据并封装发送到网络层中
运输层多路复用的要求:
- 必须要求套接字有唯一标识符
- 每个报文段都有特殊字段来指示该报文所需要交付到的套接字
特殊字段:这里的特殊字段主要指的是源端口号字段、目的端口号字段,以及其他字段(后面介绍)
端口号为16比特位,大小在0 ~ 65535之间,0 ~ 1023范围内的是周知端口号
2.2.1 无连接的多路复用与多路分解
就是UDP嘛...所以只需要客户端在发送的时候将源端口和目的端口号都打包发送的话,并且由于主机是多线程,每个进程有自己的UDP套接字和相应端口号,这样对于服务端UDP连接来说就可以多路复用到各个套接字上了。
UDP套接字是由一个二元组全面标识的,包含一个目的地IP地址和目的地端口号所以如果两个UDP报文段有相同的源地址,但是没有相同的目的地IP和端口号,也是无法传到一个相同的套接字,相反则可以。
2.2.2 面向连接的多路复用与多路分解
TCP套接字和UDP的差别是TCP套接字包含主机IP及COM号,是一个四元组
其他的没啥区别,所以TCP能建立可靠连接
2.2.3 Web服务器与TCP(没啥可讲的)
2.3 无连接运输:UDP
UDP制作了运输协议所能做的最少的工作,除了复用/分解和少量的差错检测之外,没有什么其他工作了。UDP基本就是在直接跟IP打交道。
使用UDP的理由:
- 关于发送什么数据以及何时发送的应用层控制更加精细:因为TCP有拥塞控制机制,在有些情况延迟高,他不管要花多长时间才能交付成功,只负责交付成功。所以不如UDP好使,有报文随时发送
- 无需建立连接:所以也不存在建立连接的时延,所以DNS通常都运行在UDP上
- 无连接状态:TCP需要在端系统中维护连接状态,包括接收和发送缓存、拥塞控制参数、序号以及确认好,乱八七糟一大堆,很烦。
- 分组首部开销小:TCP报文有20个字节的首部开销,UDP只有8个字节
2.3.1 UDP报文段结构(未看)
2.3.2 UDP检验和(未看)
2.4 可靠数据传输原理
目前只讨论单向传输
2.4.1 构建可靠数据传输协议
rdt1.0:rdt1.0是经完全可靠信道的可靠数据传输
发送方:兄弟,你的快递(丢过去)
接收方:好的(默默接受)
理想的认为中间不会出问题rdt2.0:rdt2.0经具有比特差错信道的可靠数据传输
发送方:兄弟,你的快递,收到了不?(发送快递)
接收方:收到了(向发送方发送ACK 就是ok的意思)
发送方:兄弟,你的快递,收到了不?
接收方:没收到呢(向发送方发送NAK 没收到等待发送方重新发送一遍)rdt2.1:rdt2.1就是为了防止在回传ACK,NAK的时候出现问题
发送方:兄弟,你的第0个快递,接着
接收方:收到了第0个快递(向发送方发送ACK0)
这里表示收到了第0个快递,接收方等待第1个快递,但是在回传ACK的时候,出现了比特翻转,变成了ACK1(这里表明接收方接到了第1个快递)那么发送发就以为自己刚才发的是1号快递,就会把0号快递再发一次,但是接收方知道自己收到的是0号快递,就会拒绝这个重发的0号快递。避免重复。rdt2.2:rdt2.2就是简化了2.1的操作,只有ACK
发送方:你的0号快递
接收方:我收到了0号快递,记得把1号快递给我(向发送方发送ACK,1 然后等待发送方把1号快递给你)
那假设我没接到0号快递
发送方:你的0号快递
接收方:我没接到0号,你再给我发一遍(向发送方发送ACK,0 等待发送方重发0号快递)rdt3.0:rdt3.0在rdt2.2的基础之上处理了数据包丢失的情况,增加了计时器的机制,如果在RTT时间段内,发送方没有接收到反馈信息,那么发送方默认数据包已经丢失了,会自动重传。
发送方:兄弟,你0号的快递,收到了吗?
发送方:兄弟,在吗?
发送方:兄弟?
发送方:算了我重发一次吧
由于分组信号在0与1之间交替,所以又被称为比特交替协议
2.4.2 流水线可靠数据传输协议
rdt3.0最大的问题在于他是一个停等协议,就是不传完当前数据不会再传下一个,而来来回数据传输ACK的时候无法传输别的数据。解决方法就是不以停等的方式运行,允许发送方发送多个分组而无需等待确认,称为流水线**技术
流水线操作带来以下的影响
- 必须增加序号范围,不能只是0和1
- 协议发送方和接收方需要缓存多个分组
- 所需序号范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏和延时过大的分组。解决流水线的差错恢复主要有两个基本方法:回退N步和选择重传
2.4.3 回退N步(GBN,Go-Back- N)
这样N称为滑动窗口的窗口长度,GBN通常被称为滑动窗口协议.
图中对于每一个部分写的十分详细.
GBN发送方必须响应三种类型的事件:
- 上层调用:如果上层调用了,首先GBN检查自己的发送窗口有没有满,如果满了的话就一会在接受,如果没满,直接产生一个分组并将其发送,并相应的更新变量。
- 收到一个ACK:在GBN中,对于序号为n的分组的确认采用累计确认的方式,表明接受方已经正确接收到序号为n的以前且包括n在内的所有分组。
- 超时事件:定时器用于恢复数据和确认分组的丢失,如果出现超时,发送方重新传递所有已经发送的但是还没有被确认过的分组
GBN接收方同样十分简单:如果一个序号为n的分组被正确的接收到了,并且按照顺序(上一次是n-1),则接收方为分组n发送一个ACK证明成功了,在除此之外的其他情况下发送方都丢弃该分组,并且按照最近接收的分组发送ACK,证明我只接收到了这个序号,无需发送后面的序号。
当然,我们可以看到GBN的优点和缺点,优点就是GBN发送很简单,不需要过多的缓存失序数据,有数据发生错误就直接抛弃,所以接收方唯一需要维护的信息就是窗口的上下边界。
(GBN综合了序号、累计确认、检验以及超时/重传操作)
2.4.4 选择重传(SR,Selective Repeat)
选择重传协议让发送方仅重传那些它怀疑在接收方出错的分组而避免了不必要的重传,这种个别的、按需重传要求接收方逐个确认正确接收的分组.
发送方:仅仅重传那些它怀疑在接收方出错的分组而避免了不必要的重传
接收方:确认所有分组,但是只选择正确序号的(按序号的)接收,其余的失序分组缓存到缓存区,知道所有的丢失分组(也就是前序分组)都被接收到为止
发送方具体操作
- 从上层收到数据后,SR检查下一个用于该分组的序号,如果序号位于发送方的窗口内部,则数据打包发送,否则就缓存数据,要么就将其返回给上层以便下次传输
- 超时,定时器方式用来丢失分组,每个分组都要有自己的逻辑定时器,因为超时发送后只能发送一个分组,所以每个分组自己判断是否超时
- 收到ACK,如果收到ACK的分组序号在发送端窗口内部,则把这个已经确认接受的分组标记为已经接受,如果这个分组的序号是send_ base,基序号移动到具有最小信号的未确认分组处,如果窗口移动并且有序号落在窗口内的未发送分组,则发送这些分组
接收方具体操作
- 对于接收方窗口之内的分组,无条件接收;SR接收方将确认一个正确接收的帧而不管其是否按序。失序的帧将被缓存,并返回给发送方一个该帧的确认帧(收到谁确认谁),直到所有帧(即序号更小的帧)皆被收到为止,这时才可以将一批帧按序交付给上层,然后向前移动滑动窗口。
如果收到了窗口下界之前的帧,就返回一个ACK。其他情况,就忽略该帧。
窗口长度必须小于与等于序号空间大小的一半
2.5 面向连接的运输:TCP
2.5.1 TCP连接
为什么说TCP是面向连接的,而UDP并不是,原因就在于TCP在连接之前会执行三次握手程序(其实是两次握手,最后一次握手是数据传输阶段,但是就直接说是三次握手了),UDP的连接并不需要实现建立连接。且TCP是只在端系统中运行的,而不在中间的网络元素(路由器和链路层交换机中运行)。
TCP提供的是全双工服务,意味着进程A可以和进程B互相发送数据。TCP提供的服务也是点对点的,这意味着TCP连接只能由两台主机构成。
当TCP三次握手之后,客户就与服务器建立起连接,客户端通过套接字传递数据流,一旦通过应用层的套接字之后,就由TCP来进行数据流控制了,TCP将这些数据引导到该连接的发送缓存之中,这样TCP就会从缓存中拿起数据扔到网络层通过IP开始传输。注:该连接两端都有缓存区,发送缓存和接收缓存,应用层分别从两个缓存区发送和接收。
TCP可以从缓存区中拿出俩放入网络层进行传输的数据数量受限于最大报文长度(MSS),MSS通常根据最初确定的由本地发送主机发送的最大链路层帧长度(即所谓的最大传输单元来确定)。最大传输单元应该是MSS+各种报文头部
TCP为每一块客户数据配上一个TCP首部,从而形成多个TCP报文段
2.5.2 TCP报文段结构
TCP报文段由首部字段和一个数据字段组成,上图是TCP的报文段的结构,首部包含源端口号和目的端口号,被用于多路复用与多路分解。同时和UDP一样,TCP包括检验和字段。TCP同时包含以下的字段:
- 32比特的序号字段和32比特的确认号字段:实现可靠数据传输服务
- 16比特的接受窗口字段:用于流量控制,该字段是指示接收方愿意接受的字节数量
- 4比特的首部长度字段:指示以32比特的字为单位的TCP首部字段(TCP首部典型长度是20字节,前提是选项字段为空)
- 可选与变长的选项字段:用于发送方与接收方协商最大报文段长度(MSS)
- 6比特的标志字段:各种flag,比如ACK,等等。
- 序号和确认号
这是TCP报文段最重要的两个字段
一个报文段的序号是该报文段首字节的字节流编号,而不是建立在传送的报文段的序列上,而是建立在传送的全体字节流上。
确认号比较难办一些,主机A填充进报文段的确认号是主机A期望从主机B收到的下一字节的序号。因为TCP之确认该流中至第一个丢失字节为止的字节,所以TCP也被称为提供累计确认(含义就是收到了1-200和300-400,但是TCP发送的报文段确认号还是201,不是401)
2.5.3 往返时间的估计与超时
TCP和前文的rdt协议一样,也是依靠超时/重传机制来处理报文段的丢失问题。连接的往返时间被称为RTT(一个报文段发出到他被确认的时间)。
- 如何确定往返时间?(暂时不看)
- 设定和管理重传超时间隔(暂时不看)
2.5.4 可靠数据传输
因为IP传输是不可靠的,他是尽全力交付数据,但是不保证是不是可靠的。所以TCP在IP不可靠的尽力而为服务上创建了一种可靠数据传输服务。这个服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流。
TCP保证可靠数据传输一共由二个部分组成
- 定时重传机制,这个没什么好说的,就是重传具有最小序号但仍未应答的报文段。
- 收到ACK:就是使用ACK确认机制,如果ACK收到了就把当前最早未被确认的字节号+1。
根据上述内容,提出了超时间隔加倍,这个意思就是每次TCP重传都会将下一次的超时间隔设为先前值的两倍,这样的目的就是因为定时器过期很可能是由于网络拥塞引起的,如果客户端持续重组,会使拥塞更加的严重。相反,TCP使用这样的方式,每个发送方的重传都是经过越来越长的时间间隔后进行的。
除了这个之外,我们还使用快速重传机制。由于超时重传提高了端到端的时延,所以发送方可以在超时事件发生之前通过注意所谓的冗余ACK来较好的检测到丢包情况。冗余ACK就是再次确认某个报文段的ACK。
当一个报文段丢失时,会等待一定的超时周期然后才重传分组,增加了端到端的时延。
当一个报文段丢失时,在其等待超时的过程中,可能会出现这种情况:其后的报文段已经被接收端接收但却迟迟得不到确认,发送端会认为也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。
幸运的是,由于TCP采用的是累计确认机制,即当接收端收到比期望序号大的报文段时,便会重复发送最近一次确认的报文段的确认信号,我们称之为冗余ACK(duplicate ACK)。如图所示,报文段1成功接收并被确认ACK 2,接收端的期待序号为2,当报文段2丢失,报文段3失序到来,与接收端的期望不匹配,接收端重复发送冗余ACK 2。
这样,如果在超时重传定时器溢出之前,接收到连续的三个重复冗余ACK(其实是收到4个同样的ACK,第一个是正常的,后三个才是冗余的),发送端便知晓哪个报文段在传输过程中丢失了,于是重发该报文段,不需要等待超时重传定时器溢出,大大提高了效率。这便是快速重传机制。
- 为什么是三次冗余ACK:(还未研究)
是回退N步(GBN)还是选择重传(SR)?
TCP的差错机制更像是GBN和SR的混合体,名称叫做选择确认
这里的回退N步只维护当前已发送但未被确认的最小序号,和下一个要发送的字节的序号,抛弃其他所有的数据,TCP和这种方式类似,但是不会抛弃其他数据,而是缓存下来其他的数据,等到需要的序号到达之后再接收这些数据。
2.5.5 流量控制(简略)
TCP为他的应用程序提供了流量控制服务,为了消除发送方使得接收方缓存溢出的可能性。
TCP通过让发送方维护一个接收窗口的变量来提供流量控制。通俗的说,接收窗口用于给发送方一个指示——该接收方还有多少可用的缓存空间。因为TCP是全双工通信,那么在连接的两端的发送方都要维护一个接收窗口。
2.5.6 TCP连接管理
三次握手连接建立过程:
- 第一步:客户端TCP向服务器端TCP发送一个特殊的TCP报文段。这个报文段被叫做SYN报文段,因为其中有一个标志位(SYN比特)被置1。另外,客户端还会随机选择一个初始序号(client_isn),并将此编号放置于该起始的TCP SYN报文段的序号字段中。该报文段会被封装在一个IP数据报中,并发送给服务器。
- 第二步:当TCP SYN报文段中的IP数据发送到主机时,主机提取TCP报文段并分配TCP缓存和变量,并向该客户TCP发送允许连接地报文段,该报文段将SYN比特置为1,其次,该报文段的client_isn + 1,最后服务器选择一个server_isn,并将其和client_isn一样封装并发送到客户端,该报文段被称为SYNACK报文段。通俗来说,服务器收到了客户端建立的SYN分组,该分组带有初始序号client_isn。服务端同意建立该连接,我的初始序号是server_isn。
- 第三步:在收到SYNACK后,客户也给该连接分配缓存和变量,然后将server_isn + 1并发送给服务端,同时SYN比特被置为0,代表连接已经被建立完成,这个阶段可以携带客户到服务器的数据。
连接关闭过程:
- 客户发送一个FIN比特,被设置为1,告诉服务端我要断开连接了。
- 服务端收到之后回送一个确认报文段(ACK),后发送一个服务端FIN比特,也是设置为1
- 接收端收到后进行确认(发送给服务器一个ACK)
2.5.7 SYN洪范攻击(未看)
2.6 拥塞控制原理
具有理想拥塞控制的网络,在吞吐量达到饱和之前,网络吞吐量 = 输入负载。输入负载超过限度时,由于网络资源访问受限,吞吐量停止增长。即损失了一部分输入负载,比如输入的某些分组被某个节点丢弃。
实际网络如果不进行拥塞控制,吞吐量对应输入负载的增长率逐渐降低,即吞吐量未达到饱和前,就损失了一部分输入负载,进入轻度拥塞状态。吞吐量达到某一值时,吞吐量随输入负载增大而下降,进入拥塞状态。输入负载增大到某一值时,吞吐量下降到0,死锁。
拥塞网络的代价:
- 当分组的到达速率接近链路容量时,分组经历巨大的排队时延。
- 发送方在遇到大时延时所进行的不必要重传回引起路由器利用其链路带宽来转发不必要的分组副本。
- 当一个分组沿着一条路径被丢弃时,每个上有路由器用于转发该分组到丢弃该分组而使用的传输容量最后被浪费掉了。
2.6.2 拥塞控制方法
可以根据网络层是否为运输层拥塞控制提供了显式帮助,来区分拥塞控制方法:
- 端到端拥塞控制:在端到端的控制方法中,网络层没有为运输层拥塞控制提供显式支持。端系统必须通过对网络行为的观察来判断(分组丢失与时延)
- 网络辅助的拥塞控制:路由器可以向发送方提供关于网络中拥塞状态的显示反馈信息,用一个比特位来指示链路中的拥塞情况
对于网络辅助的控制,也有两种不同类型:
直接由网络路由器发给发送方,或者路由器标记或者更新一个从发送方发到接收方的分组中的某个字段来指示拥塞的产生(需要经历一个RTT)
2.7 TCP拥塞控制
原理:如果TCP感知到端到端路径上没有什么拥塞,就提高发送速率,反之相反
- 如何限制发送流量的速率:通过一个拥塞窗口cwnd,TCP除了跟踪接收缓存发送缓存和几个变量之外,还跟踪一个叫做拥塞窗口的变量。简单来说,发送方未被确认的数据不能超过cwnd和rwnd的最小值。
- 如何感知发生了拥塞:要么出现超时,要么出现冗余ACK。TCP也是自计时的,因为随着发送速率加快,cwnd增加速度也变快,反之亦然,这意味着TCP使用确认来触发(或计时)增大它的拥塞窗口长度。
- TCP怎么样才能确定它应当发送的频率:基于以下的指导原则
- 当丢失报文段时,意味着拥塞,应降低速率
- 一个确认的报文段代表网络正在交付发送方的报文段,所以当对先前未确认报文段的确认到达的时候,能够增加发送方的速率
- 不断增加ACK,直到出现丢包,再停止增加转而减少,并继续开始检测
2.7.1 慢启动
理解很简单,在慢启动状态cwnd的值从一个MSS开始,并当传输的报文段首次被确认就增加一个MSS,这样每次如果都完美被接收的话,每次cwnd就会翻倍。
何时结束慢启动呢?
- 当出现丢包的时候就会将cwnd置为1,并重新开始慢启动过程。同时记录一个慢启动阈值ssthresh等于刚刚结束的最大cwnd/2,即当检测到拥塞时将ssthresh置为拥塞窗口长度的一半。
- 当cwnd继续增加并超过ssthresh的时候,继续翻倍就有些鲁莽了,所以从这里开始结束慢启动,并转移到拥塞避免模式,这里会更谨慎的增加cwnd。
- 如果检测到3个冗余ACK,同样结束慢启动,并开启快速重传
2.7.2 拥塞避免
(如何进入拥塞避免模式看上面)一旦进入拥塞避免模式,每次cwnd会增加一个MSS,这是一种较为保守的方法。
还有一个问题,如何结束这样的线性增长呢?
和慢启动一样,如果发生超时时间,cwnd变成1,ssthresh值变成cwnd的一半。
也可以由三个冗余ACK触发(丢包),然而这种方法相比于超时引起的结束增长不是那么剧烈:这时TCP会将cwnd值减半(加上3个MSS,因为有三个冗余的ACK),并当收到三个冗余ACK时就将ssthresh的值记录为cwnd的值的一半,接下来就进入快速恢复的状态
2.7.3 快速恢复
在这里,对于引起TCP进入该状态的缺失报文段,对收到的每个冗余ACK,cwnd的值都增加一个MSS,最终,当对丢失报文段的一个ACK到达的时候,TCP在降低cwnd后进入拥塞避免状态。如果出现超时,则和慢启动还有拥塞避免一样,cwnd变成1,ssthresh变成cwnd的一半。