传输层介于应用层与网络层之间,是计算机网络最为基本的一层,该层的协议为应用进程提供端到端的通信服务。其提供面向连接的数据流支持、可靠性、流量控制、多路复用等服务。
此层还包含了两个重要的传输层服务:TCP
和 UDP
。
由于传输层的下一层,网络层的 IP 服务是不做任何保证的,是一个不可靠服务,因此传输层就必须做一定的保障服务。
多路复用与多路分解
多路复用(Multiplexing)和多路分解(Demultiplexing),将网络层提供的主机到主机的交付服务延伸到了为运行在主机上的应用程序提供进程到进程的交付服务。
多路分解:将运输层报文段中的数据交付到正确的套接字。
多路复用:将源主机不同套接字中的数据块封装首部信息,并生成报文段传递到网络的一系列过程。
无连接的复用与分解(面向UDP)
- 利用端口号创建 Socket
DatagramSocket mySocket1 = new DatagramSocket(99111);
- UDP 的 Socket 用二元组表示
- (目的 IP,目的端口号)
- 主机收到 UDP 段后
- 检查段中的目的端口号
- 将 UDP 段导向绑定在该端口号的 Socket
- 来自不同源 IP 地址和/或源端口号的 IP 数据包被导向同一个Socket
有连接的复用与分解(面向TCP)
- TCP 的 Socket 用四元组标识
- 源IP地址
- 源端口号
- 目的 IP 地址
- 目的端口号
- 接收端利用所有的四个值将 Segment 导向合适的 Socket
- 服务器可能同时支持多个 TCP Socket
- 每个 Socket 用自己的四元组标识
- Web 服务器为每个客户端开不同的 Socket
UDP
UDP,即:User Datagram Protocol,是一个基于 IP 的传输层协议,其遵循 “Best Effort” 理念,是一种无连接的协议(其在传输数据之前发送方与接收方之间并不会先进行握手)。
UDP 主要有以下优点:
- 无需建立连接(减少延迟)
- 实现简单:无需维护连接状态
- 头部开销少
- 没有拥塞控制应用可以更好地控制发送时间和速率
正由于这些特点,UDP 通常用于流媒体以及 DNS 服务。现在某些公司或者机构开始研究在 UDP 上实现可靠数据传输,其主要思路也是加入错误恢复机制。
基础概念
关于 UDP 的基础概念,主要有报文段结构,以及UDP校验和。
报文段结构
UDP 报文段大概可分为两大部分:头部和数据。头部只有 4 个字段,每个字段两个字节,也就是 16 比特。4 个字段分别为:
- 源端口号
- 目的端口号
- 报文长度:首部加数据的总长度
- 校验和
如下图所示:
UDP 校验和
校验和的目的主要是为了检测 UDP 段在传输中是否发生了错误,其主要算法如下:
- 首先将段的内容失为一个个 16-bit 的整数
- 然后进行计算:
- 计算所有整数的和(如果有进位,将进位回卷,继续相加)比如:
10 + 10
有一进位1
,然后在加在结果上,也就是10 + 10 = 00 + 1 = 01
(这是两位的简单举例,校验和虽是 16 位的,但是思路是一致的) - 将值按位取反
- 计算所有整数的和(如果有进位,将进位回卷,继续相加)比如:
发送方按照上述算法计算完成之后,将校验和放入 Checksum
字段;接收方收到之后也按照上述方法计算,并将计算结果与Checksum
进行比较,如果不相等,便可判定出现了错误(需要注意的是,相等也不能说明没有错误)。
TCP
TCP 协议是建立在可靠数据传输基本原理中的,可靠数据传输是一个非常重要且比较偏理论点,所以在此篇博客中,我并不打算详细地解释可靠数据传输原理,以后可能会单独写一篇。
TCP,即:Transmission Control Protocol ,不同于UDP,其是一个面向连接(两个进程互相发送数据之前,必须先进行“握手”)的协议 。
报文段结构
了解 TCP 协议,最为基础的内容便是了解其报文段结构,其报文段如下图所示:
- 【第一行】:16 比特的源端口号和目的端口号
- 【第二三行】:32 比特的序号字段和确认号字段(用于实现可靠数据传输)
- 【第四行左】:
- 4 比特的首部长度字段(以字为单位,每单位 32 比特),TCP 由于 Options(选项) 字段的原因,其首部长度是可变的,所以需要记录首部长度(一般来说,Options 选项字段为空,其典型首部长度为20字节)
- 4 比特的保留字段
- CWR、ECE (这两个用于显式拥塞通告)和 6 比特的标志字段:
- URG:紧急数据(不使用)
- ACK:用于指示确认字段中的值是有效的
- PSH:指示接收方应立即将数据交给上层(不使用)
- RST、SYN、FIN:用于连接的建立与拆除
- 【第四行右】:接收窗口大小,以字节为单位。
- 【第五行左】:校验和,计算方法与 UDP 的一致,不过与 UDP 不同的是,其必须要存在。
- 【第五行右】:紧急指针,在 URG 标志位有值时生效;将这个数值加到序号上就得到版文段数据部分中最后一个紧急字节的编号
- 【第六行】:选项字段,用作协商报文长度时;或者在高速网络环境下用作窗口调节因子时。
流量控制
流量控制,是为了消除发送方使接收方缓存溢出的可行性,也就是说,这是一个速度匹配服务,将发送发与接收方之间的读取速率进行匹配。
其主要方式就是一个称之为速度匹配机制的东西,发送方维护一个接收窗口(receive window)来提供流量控制,其具体措施为:
- 接收方通过在Segment的头部字段将接收窗口的大小告诉发送方
- 发送方限制自己已经发送的但还未收到的ACK的数据不超过接收方的空闲接收窗口的尺寸
这样会有一个问题,发送方在收到接收方传来接收窗口为0的情况下,就不再向其发送信息了,这样发送不就断开了吗?
为了解决这个问题,TCP规范规定,接收方接收窗口为0时,发送方仍要发送只有一个字节数据的报文段,直至接收方可以继续接收真实数据为止。
连接管理
这部分主要分析和了解,如何建立和拆除一条TCP连接!
三次握手
- 客户主机向服务器发送一个特殊的TCP报文段:
- 报文段不包含应用层数据,
SYN
标志位被置为1 - 随机选择初始序号,置于序号字段中。
- 报文段不包含应用层数据,
- 第二步:服务器收到
SYN
之后,答复SYN
ACK
段- 服务器分配自己的缓存
- 设置自己的报文头:
SYN
置为1;ACK
置为1并将确认号字段为客户端的初始序号+1;设置自己的初始序号
- 第三步:客户机收到
SYN
ACK
之后,答复ACK
- 客户端分配空间
- 设置报文头并发送给服务器:
SYN
置为0;ACK
置为1并将确认号字段设置为服务器初始序号+1 - 可以携带数据
为何三次握手
- 一个很简单的思路,就是为了初始化二者的 Sequence Number ,第三次握手要客户端确认收到了服务器的Sequence Number
四次挥手
- 第一步:客户机向服务器发送TCP FIN 控制segment
- 用来关闭客户端到服务端的数据传送
- 客户端进入FIN_WAIT_1状态
- 第二步:服务器收到FIN,回复ACK。
- 服务端进入 CLOSE_WAIT 状态
- 第三步:服务器关闭连接,发送FIN
- 用来关闭服务端到客户端的数据传送
- 服务端进入 LAST_ACK 状态
- 第四步:客户机收到FIN,回复ACK
- 客户机进入 TIME_WAIT 状态
- 客户机发送ACK响应
- 服务端进入 CLOSE 状态,正式关闭!
其服务端和客户端所经历的阶段如下图所示: