计算机网络体系结构的划分主要有三种方式,分别是OSI的七层体系结构,教学用途划分的五层协议体系结构以及工程中实际应用的TCP/IP的体系结构。它们的体系结构如下图所示。这里我们只了解下五层协议的体系结构。
应用层: 体系结构中的最高层。其主要任务是通过应用进程间的交互来完成特定网络应用。。应用层协议定义的是应用进程间通信和交互的规则。
运输层:主要负责向两个主机中进程间的通信提供通用的数据传输服务。运输层具有复用和分用的功能。
网络层:负责为分组交换网上的不同主机提供通信服务。网络层把运输层的产生的报文段或用户数据报封装成分组或包进行传送。网络层的另一个任务是选择路由。
数据链路层:数据链路层将网络层交下来的IP数据报封装成帧,在两个相邻结点间的链路上传送帧。
物理层:物理层主要考虑的问题是,比特以多大的电压在线路上传输以及接收方如何识别发送方发送的比特。
网络层
1、IP地址
我们一般说的IP都是指IP地址,那么到底什么是IP地址呢?其实IP地址就是给每个连接在因特网上的主机(或路由器)分配一个在全世界范围是唯一的 32 位或128位的标识符。
IP地址是由网络号和主机好组成的,即
IP 地址 ::= { <网络号>, <主机号>}
其中,网络号标识当前主机所在局域网的网络号,主机号则是由当前所在局域网为每台主机分配的号码。
2、IP地址与硬件地址
物理地址(硬件地址)是数据链路层和物理层使用的地址,而IP地址是网络层和以上各层使用的地址。
对于IP地址向物理地址的转换我们则是通过地址解析协议ARP解决的。每一个主机都设有一个 ARP 高速缓存(ARP cache),里面有所在的局域网上的各主机和路由器的 IP 地址到硬件地址的映射表。当主机 A 欲向本局域网上的某个主机 B 发送 IP 数据报时,就先在其 ARP 高速缓存中查看有无主机 B 的 IP 地址。如有,就可查出其对应的硬件地址,再将此硬件地址写入 MAC 帧,然后通过局域网将该 MAC 帧发往此硬件地址。当主机 B 收到 A 的 ARP 请求分组时,就将主机 A 的这一地址映射写入主机 B 自己的 ARP 高速缓存中。这对主机 B 以后向 A 发送数据报时就更方便了。如果主机A的高速缓存中没有主机B的IP地址,A的ARP进程就在本局域网内广播发送一个ARP请求分组,本局域网内所有主机运行的ARP进程都能收到该ARP请求分组,B主机收下该分组,并向A发送自己地址信息,其余主机则不理睬这个请求分组。如果所要找的主机和源主机不在同一个局域网上,那么就要通过 ARP 找到一个位于本局域网上的某个路由器的硬件地址,然后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络。剩下的工作就由下一个网络来做。
3、IP数据报的格式
- 版本——占 4 位,指 IP 协议的版本目前的 IP 协议版本号为 4 (即 IPv4)。
- 首部长度——占 4 位,可表示的最大数值是 15 个单位(一个单位为 4 字节)因此 IP 的首部长度的最大值是 60 字节。
- 区分服务——占 8 位,只有在使用区分服务(DiffServ)时,这个字段才起作用。在一般的情况下都不使用这个字段 。
- 总长度——占 16 位,指首部和数据之和的长度,单位为字节,因此数据报的最大长度为 65535 字节。总长度必须不超过最大传送单元 MTU(数据帧中数据字段的最大长度)。
- 标识(identification) 占 16 位,它是一个计数器,用来产生数据报的标识。
- 标志(flag) 占 3 位,目前只有前两位有意义。
标志字段的最低位是 MF (More Fragment)。MF = 1 表示后面“还有分片”。MF = 0 表示最后一个分片。
标志字段中间的一位是 DF (Don’t Fragment) 。只有当 DF = 0 时才允许分片。 - 片偏移(13 位)指出:较长的分组在分片后某片在原分组中的相对位置。片偏移以 8 个字节为偏移单位。
- 生存时间(8 位)记为 TTL (Time To Live)数据报在网络中可通过的路由器数的最大值。路由器在转发数据报之前就把TTL值减1。若TTL的初始值为1,那么这个数据报只能在本局域网内传送。
- 协议(8 位)字段指出此数据报携带的数据使用何种协议以便目的主机的 IP 层将数据部分上交给哪个处理过程 。
- 首部检验和(16 位)字段只检验数据报的首部不检验数据部分。这里不采用 CRC 检验码而采用简单的计算方法。
- 源地址和目的地址都各占 4 字节。
分组转发算法
1. 从数据报的首部提取目的主机的 IP 地址 D, 得出目的网络地址为 N。
2. 若网络 N 与此路由器直接相连,则把数据报直接交付目的主机 D;否则是间接交付,执行3。
3. 若路由表中有目的地址为 D 的特定主机路由,则把数据报传送给路由表中所指明的下一跳路由器;否则,执行4。
4. 若路由表中有到达网络 N 的路由,则把数据报传送给路由表指明的下一跳路由器;否则,执行5。
5. 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;否则,执行6。
6. 报告转发分组出错。
划分子网
划分子网纯属一个单位内部的事情。单位对外仍然表现为没有划分子网的网络。从主机号借用若干位作为子网号。划分子网后,IP地址变为了三级结构。
IP地址 ::= {<网络号>, <子网号>, <主机号>}
利用子网掩码与IP地址相“与“(AND)可以得出IP地址所在的网络号或子网号。
划分子网下的路由转发分组算法:
(1) 从收到的分组的首部提取目的 IP 地址 D。
(2) 先用各网络的子网掩码和 D 逐位相“与”,看是否和
相应的网络地址匹配。若匹配,则将分组直接交付。
否则就是间接交付,执行(3)。
(3) 若路由表中有目的地址为 D 的特定主机路由,则将
分组传送给指明的下一跳路由器;否则,执行(4)。
(4) 对路由表中的每一行的子网掩码和 D 逐位相“与”,
若其结果与该行的目的网络地址匹配,则将分组传送
给该行指明的下一跳路由器;否则,执行(5)。
(5) 若路由表中有一个默认路由,则将分组传送给路由表
中所指明的默认路由器;否则,执行(6)。
(6) 报告转发分组出错。
无分类编址CIDR(构成超网)
无分类的两级编址的记法是: IP地址 ::= {<网络前缀>, <主机号>}
CIDR使用斜线记法,就是在IP地址后面加上一个斜线 ”/“然后写上网路前缀的所占位数,CIDR把网络前缀相同的连续的IP地址组成”CIDR地址块“。例如:128.14.32.0/20 表示该地址的前20位为网络前缀。那么该地址的主机号就是12位。
运输层
用户数据报协议UDP
UDP的主要特点:
- UDP是无连接的
- UDP使用最大努力交付
- UDP是面向报文的:对应用层交下来的报文,不合并也不拆分,给多长的报文一次性就发送多大的报文。
- UDP没有拥塞控制
- 支持一对一,一对多,多对一和多对多的通信
- 首部开销小(相对TCP来讲)
UDP 的首部格式:
源端口:用来告诉对方自己所在应用进程的端口号。
目的端口:对方当前进程的端口号。
长度:用户数据报的长度。
检验和:检验UDP用户数据报是否有错。
传输控制协议TCP
TCP的主要特点:
- 面向连接的运输层协议
- TCP连接是一对一的
- TCP提供可交付的服务
- 全双工通信
- 面向字节流
套接字 socket = (IP地址: 端口号)
每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。
TCP 报文段的首部格式
* 源端口和目的端口字段——各占 2 字节。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。
* 序号字段——占 4 字节。TCP 连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
* 确认号字段——占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。
* 数据偏移(即首部长度)——占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位是 32 位字(以 4 字节为计算单位)。
* 保留字段——占 6 位,保留为今后使用,但目前应置为 0。
* 紧急 URG —— 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
* 确认 ACK —— 只有当 ACK = 1 时确认号字段才有效。当 ACK 0 时,确认号无效。
* 推送 PSH (PuSH) —— 接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
* 复位 RST (ReSeT) —— 当 RST = 1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
* 同步 SYN —— 同步 SYN = 1 表示这是一个连接请求或连接接受报文。
* 终止 FIN (FINis) —— 用来释放一个连接。FIN 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
* 窗口字段 —— 占 2 字节,用来让对方设置发送窗口的依据,单位为字节。
* 检验和 —— 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
* 紧急指针字段 —— 占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
* 选项———长度可变,最长可达40字节
以字节为单位的字节滑动窗口
前面我们已经知道,TCP报文是面向字节的,并且首部中还有个序号字段,用来为发送的每个字节按顺序编号。
现假设场景 A:发送方 B:接收方
当A收到B发来的确认报文段,其中窗口值为20,确认号ACK = 31(这表示B希望收到下一个字节的序号为31,而31之前的序号已经收到了),窗口值20表示B现在可以一次性接收20个字节。A构造出自己发送窗口如下图所示:
A的发送窗口大小由后沿和前沿共同确定(即前沿与后沿夹着的字节数与窗口值等大)。后沿可能前移(收到了新的确认)或不动(没收到新的确认)。前沿可能前移(收到确认号而且B的窗口没有变小)或不动(收到了确认号但是B的窗口变小了或没收到确认而且B的窗口大小不变)。对于发送窗口前沿后移的情况,TCP标准不建议这样做。
B只能对按顺序收到的数据中的最高序号给出确认。即假设B现在收到了33,34序号的字节,但是B给出的确认号还是31,因为B之前只是收到30这个确认号,现在收到的33,34并没有按顺序收到,直到31,32都收到后,B给出的确认号才是35。然后A的后沿前移,前沿根据B给出的窗口值确定。
还有一点值得注意,就是发送方和接收方都设有缓存机制。如下图所示:
发送缓存用来暂存:
- 发送应用程序传送给发送方 TCP 准备发送的数据;
- TCP 已发送出但尚未收到确认的数据。
接收缓存用来暂存:
- 按序到达的、但尚未被接收应用程序读取的数据;
- 未按序到达的数据。
TCP的流量控制
流量控制:就是让发送方的发送速率不要太快,要让接收方来得及接收。
利用滑动窗口机制可以实现对发送方的流量控制。假设A向B发送数据,每次B发送确认报文的时,都会告诉A自己的接收窗口的大小,那么A的发送窗口值就不能超过B给出的窗口值大小。通过这种方式保证发送和接收的相对一致。
TCP的拥塞控制
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要破坏。这种情况叫做拥塞。
拥塞控制就是防止过多的数据注入到网络中,这样就可以是网络中的路由器或链路不致过载。
几种拥塞控制方法
1、慢开始和拥塞避免
发送方维持了一个叫做拥塞窗口cwnd的状态变量,其值大小取决于网络的拥塞程度。只要网络没有出现阻塞,拥塞窗口就再增大一些,但只要网络出现拥塞,拥塞窗口就减小。
慢开始算法:在主机刚刚开始发送报文段时可先设置拥塞窗口 cwnd = 1,即设置为一个最大报文段 MSS 的数值。在每收到一个对新的报文段的确认后,将拥塞窗口加 1,即增加一个 MSS 的数值(发送的字节数变为了原来的2倍)。用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
慢开始门限ssthresh就是一个为了防止拥塞窗口增长过大引起网络拥塞的变量。
ssthresh用法:
- 当 cwnd < ssthresh 时,使用慢开始算法。
- 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
- 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
拥塞避免算法:让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍,使拥塞窗口 cwnd 按线性规律缓慢增长。
当发送方判断网络出现拥塞时需做以下几步:
ssthresh=min(cwnd/2, 2)
cwnd=1
重新执行慢开始算法
拥塞控制图解过程,这里假定了cwnd=24时,网络出现超时:
乘法减小:指不论在慢开始阶段还是拥塞避免阶段,只要出现超时,就把慢开始门限ssthresh减半。
2、快重传和快恢复
快重传算法要求接收方每收到一个失序的报文段后就立即发出重复确认。这样做可以让发送方及早知道有报文段没有到达接收方。发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段。如图:
与快重传配合使用的还有快恢复算法:当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半。但接下去不执行慢开始算法。由于发送方现在认为网络很可能没有发生拥塞(因为发送方收到了连续重复确认报文),因此现在不执行慢开始算法,即拥塞窗口 cwnd 现在不设置为 1,而是设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。 如图所示:
发送时还需要注意接收窗口的值:发送方窗口的上限值 = Min [rwnd,cwnd]
TCP的运输连接管理
三次握手建立TCP连接的过程如图所示:
- A 的 TCP 客户进程向 B 发出连接请求报文段,其首部中的同步位 SYN = 1(SYN报文段不能携带数据,但要消耗掉一个序号),并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
- B 的 TCP 收到连接请求报文段后,如同意,则发回确认。B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x = 1,自己选择的序号 seq = y(不能携带数据,同样消耗掉一个序号)。
- A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y + 1。A 的 TCP 通知上层应用进程,连接已经建立(若携带数据需要消耗掉一个序号,否则不消耗)。
- B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。
为什么是3次握手而不是2次呢,主要是为了防止已失效的连接请求报文段又传送到了B。所谓已失效是指A发出的连接请求报文段并没有丢失,而是在网络中滞留了,延误到连接释放后才到达B。
四次挥手过程如图:
- 数据传输结束后,通信的双方都可释放连接。现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认。
- B 发出确认,确认号 ack = u + 1,而这个报文段自己的序号 seq = v。TCP 服务器进程通知高层应用进程。从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态。B 若发送数据,A 仍要接收。
- 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。发出的连接释放报文段须使FIN = 1。并重复上次已发送的确认号ack = u + 1,序号w为B上次已发送数据的最后一个字节的序号加1。
- A 收到连接释放报文段后,必须发出确认。在确认报文段中 ACK = 1,确认号 ack = w + 1,自己的序号 seq = u + 1。 B一收到这个确认报文段,就进入CLOSED状态。
- TCP 连接必须经过时间 2MSL 后才真正释放掉。
TCP的有限状态机
- 粗实线箭头表示对客户进程的正常变迁。
- 粗虚线箭头表示对服务器进程的正常变迁。
- 细线箭头表示异常变迁。