传输层
1. 传输层作用
传输层向它上面的应用层提供通信服务,还要对收到的报文进行差错检测。
IP 协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。从传输层的角度看,通信的真正端点并不是主机而是主机中的进程,也就是说,端到端的通信是应用进程之间的通信。
网络层为主机之间提供逻辑通信,而传输层为应用进程之间提供端到端的逻辑通信。
传输层要能正确地将数据交付给指定应用进程,就必须给每个应用进程赋予一个标识。在 TCP/IP 网络中,使用一种与操作系统无关的协议端口号(protocol port number)来实现对通信的应用程序的标识。
此外,端口号也支撑了传输层的两个重要特征:
- 多路复用(Multiplexing):在发送端,当多个应用程序需要使用同一传输层协议(如 TCP 或 UDP)时,协议端口号允许在单个传输层连接上同时发送多个数据流。这样可以节省资源并提高效率,因为不必为每个应用程序建立单独的连接。
- 多路分解(Demultiplexing):在接收端,通过协议端口号,传输层可以将接收到的数据包正确地交付给目标应用程序。这样,接收端的传输层能够根据目标端口号将接收到的数据包分发给相应的应用程序,从而确保正确的数据传输。
2. 传输层协议
传输层根据应用程序的不同需求,需要有两种不同的运输协议,即面向连接的 TCP 和无连接的 UDP:
- TCP:当使用 TCP 协议时,尽管下面的网络是不可靠的,但这种逻辑通信信道就相当于一条全双工的可靠信道;
- UDP:但当使用 UDP 协议时,这种逻辑通信信道仍然是一条不可靠信道。
3. TCP 协议
3.1 特点
传输控制协议 TCP(Transmission Control Protocol),TCP 是 TCP/IP 体系中非常复杂的一个协议,其最主要的特点是:
- 面向连接:TCP 在传送数据前必须先建立连接,数据传送结束后要释放连接,类似打电话
- 每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是点对点的(一对一)
- TCP 提供可靠交付的服务:TCP 下面的网络所提供的是不可靠的传输,因此必须采用适当的措施才能使得两个传输层之间的通信变得可靠,主要有停止等待协议、连续 ARQ 协议
- TCP 提供全双工通信
- 面向字节流
3.2 套接字
TCP 把连接作为最基本的抽象,TCP 连接的端点叫做套接字 (socket) ,套接字由端口号拼接到 IP 地址构成。每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定: $$ socket=(ip: port) \ TCPConnection::={socket_1, socket_2}={(ip_1:port_1),(ip_2:port_2)} $$
3.3 三报文握手
TCP 建立连接的过程叫做握手,是一种采用客户服务器的方式,握手需要在客户和服务器之间交换三个 TCP 报文段,故称三报文握手。
三报文握手(three way handshake, RFC 973 最新的文档中有这样的表述:three way (three message) handshake,注意 handshake 使用的是单数而不是复数,表明只是一次握手)是本教材首次采用的译名,现实中更为流行的是“三次握手”的译名,然而在实际上这是在一次握手的过程中交换了三个报文,有点像两个人见面进行一次握手时他们的手上下摇晃了三次,但这并非进行了三次握手,笔者认为三报文握手在意思的表达上更为准确。
这些术语 | 这些状态 |
---|---|
SYN 同步位 | LISTEN(收听) |
初始序号 seq | SYN-SENT(同步已发送) |
ACK 位 | SYN-RCVD(同步收到) |
确认号 ack | ESTABLISHED(已建立连接) |
上图中 B 发送给 A 的报文段也可拆分成两个报文段,可以先发送一个确认报文段($ACK=1, ack=x+1$),然后再发送一个同步报文段($SYN=1, seq=y$),这样的过程就变成了四报文握手,但效果是一样的。
为什么 A 最后还要发送一次确认呢?这主要是为了防止已失效的连接请求报文段突然又传送到了 B,因而产生错误。
为什么需要三次握手?
虽然觉得网络上没有完全正确的答案,但可以参考 TCP 三次握手和四次挥手(传输层) | JavaGuide。
3.4 四报文挥手
TCP 连接释放的过程是四报文挥手:
这些术语 | 这些状态 |
---|---|
FIN 终止控制位 | FIN-WAIT-1(终止等待 1) |
序号 seq | CLOSE-WAIT(关闭等待) |
ACK 位 | FIN-WAIT-2(终止等待 2) |
确认号 ack | LAST-ACK(最后确认) |
TIME-WAIT(时间等待) |
为什么 A 在 TIME-WAIT 状态必须等待 2MSL 的时间呢?有两个理由:
为什么需要四次挥手?
虽然觉得网络上没有完全正确的答案,但可以参考TCP 三次握手和四次挥手(传输层) | JavaGuide。
3.5 TCP 如何保障传输的可靠性
- 基于数据块传输:应用数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
- 对失序数据包重新排序以及去重:TCP 为了保证不发生丢包,就给每个包一个序列号,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据就可以实现数据包去重。
- 校验和 : TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
- 重传机制 : 在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。
- 流量控制 : TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。
- 拥塞控制 : 当网络拥塞时,减少数据的发送。TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。
- 接收方的接收能力由滑动窗口表示,表示接收方还有多少缓冲区可以用来接收数据。
- 网络的拥塞程度由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。
- 发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞
4. UDP 协议
用户数据报协议 UDP(User Datagram Protocol) 是无连接的,UDP 在传送数据之前不需要先建立连接,远地主机的传输层在收到 UDP 报文后不需要给出任何确认。
5. TCP v.s. UDP
TCP 与 UDP 的区别
要素 | TCP | UDP |
---|---|---|
是否面向连接 | 是 | 否 |
是否可靠 | 是 | 否 |
是否有状态 | 是 | 否 |
传输效率 | 较慢 | 较快 |
传输形式 | 字节流 | 数据报文段 |
是否提供广播或多播服务 | 否 | 是 |
首部开销 | 20 ~ 60 bytes | 8 bytes |
- 是否面向连接:UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。
- 是否是可靠传输:
- 远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。
- TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。
- 是否有状态:这个和上面的“是否可靠传输”相对应。
- TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。
- 而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了。
- 传输效率:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
- 传输形式:TCP 是面向字节流的,UDP 是面向报文的。
- 是否提供广播或多播服务:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
- 首部开销:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
什么时候选择 TCP,什么时候选 UDP?
- TCP 用于对传输准确性要求特别高的场景,比如文件传输、发送和接收邮件、远程登录等等。
- UDP 一般用于即时通信,比如:语音、 视频、直播等等。这些场景对传输数据的准确性要求不是特别高,比如你看视频即使少个一两帧,实际给人的感觉区别也不大。