计算机网络之传输层

传输层提供应用进程间的逻辑通信,UDP 和 TCP 是传输层中最重要的两种协议。TCP 协议复杂,但传输可靠。UDP 协议简单,但传输不可靠。

端口与 socket

端口是伴随传输层产生的概念,它可以将网络层的 IP 通信分送到各个通信通道,UDP 和 TCP 都是建立从一个端口到另外一个端口的通信。
socket 是操作系统提供的一个编程接口,程序可以通过 socket 来调用系统内核来处理网络协议的模块,操作系统会在传输之前根据参数来构建 UDP 或者 TCP 数据报。

UDP

UDP 是无连接的,尽最大努力交付,不保证可靠交付,面向报文的,没有拥塞控制,支持一对一、一对多、多对一和多对多,首部开销小。UDP 协议可以看成 IP 协议在传输层的一个接口,因为 IP 协议没有端口这个概念,在传输层必须是面对程序,所以要给每个程序都要有端口。
尽管 UDP 简单,但是它晚于 TCP ,因为一开始有了 TCP/IP 后发现网络负担比较大,才发明 UDP 协议来简单处理这些简单的通信。

UDP 的首部

UDP-Header

source port 代表出发端口,destination port 代表目的地端口。Length 代表 UDP 包的长度。checksum 把首部和数据部分一起都检验,在 IPv4 中 checksum 可以等于 0 ,意味可以不使用 checksum 。在 IPv6 中必须使用。

TCP

TCP 是 TCP/IP 体系中非常复杂的一个协议。TCP 是面向连接的传输层协议,只能是点对点,提供可靠交付,全双工通信,面向字节流。

分段与流

TCP 协议虚拟了文本流的通信。IP 协议不能保证数据到达的次序,但是 TCP 协议确保了数据到达的顺序与文本顺序相符合。既然是流,那么需要保证次序,因为 IP 包是有 MTU 限制,所以 TCP 只能分段进行传输。每一个 TCP 片段同样分成首部和数据两部分,首部会存有该片段的序号,这样就可以知道此刻接收到的片段位于原文本流中的顺序。

可靠性

为了避免收到的片段缺少中间的一些片段,TCP 在每收到一个正确的片段后,就向发送方发送一个 TCP 片段 ACK( acknowledge ) 。如果接收到片段编号是 L ,那么 ACK 回复就是 L+1 ,代表期望下一个片段的编号。如果发送方在一定时间内没有等到 ACK ,那么就会重新发送,知道收到片段对应的 ACK 回复。如果 ACK 回复丢失了,那么发送方还会重新发送,接收方接收到已经接受过的片段,会重新发送 ACK 回复。

滑窗

在等待 ACK 回复的过程中,网络都处于闲置状态,为了提高效率,接收方和发送方都可以采用滑窗。
对于发送方来说,左侧为已经发送并且接收到 ACK 回复的片段序列。右侧是待发送的片段。滑窗中是已经发送,但是还没有收到 ACK 回复的。假如滑窗中的序列是(5,6,7),那么如果收到 5 的 ACK 回复,滑窗就会向右移动,否则等待 5 的 ACK 回复。
对于接收方来说,左侧是已经收到并且回复了 ACK 的片段,滑窗中是期望接受的片段。同样的,接收到 5 就会向右移动,否则一直等待接受新的片段。

累计 ACK

接收方往往利用一个 ACK 回复来通知连续多个片段的成功接收,通过累计 ACK ,所需要的 ACK 回复通常可以降到 50% 。

滑窗结构

windows

窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。

连接

前面我们说了 TCP 连接是点对点的,这里的点就是指端口,一个具体的端口需要 IP 地址和端口号共同来确定。每个连接有四个参数(两个 IP,两个端口),只有有一个不同,那么就是不同的连接,注意,同一个端口上可以有多个连接。

TCP-Header

TCP 首部含有出发端口和目的地端口。每个片段都有序号,ACK 回复附着在发送的数据片段的首部中,减少 ACK 占用的交通流量,一个纯粹的 ACK 回复不传输文本流,所以不消耗序列号。

TCP-handshake

建立 TCP 连接的最重要目的就是交换双方的初始序列(ISN, Initial Sequence Number)。ISN 交换是通过 SYN 片段实现的,SYN 片段是由首部的 SYN 位来表明。所以三次握手的过程的本质就是双方互发含有自己的 ISN 的 SYN 片段。图中的 x 就是客户端的 ISN ,Y 就是服务端的 ISN 。
SYN 是在连接建立时用来同步序号,当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文段。对方若同意建立连接,应该在响应的报文中使得 SYN=1 和 ACK=1 。

TCP-firewalls

连接终结使用的是特殊片段 FIN 。连接双方交换了四片信息(两个 FIN 和两个 ACK )。client 发出最后的 ACK 回复可能丢失,server 如果没有收到 ACK 就会不断重复发送 FIN 片段,所以 client 不能立刻关闭,必须确认 server 接收到了 ACK 。client 发送 ACK 然后等待 2MSL( Maxmium Segment Lifetime)。如果等待了 2MSL 还没有收到 FIN ,那么 client 可以认为 ACK 已经成功接受了。

流量控制

TCP 会根据情况来自动改变滑窗大小,流量控制是指接收方将窗口大小通知给发送方,从而指导发送方修改窗口大小,该信息放在 TCP 结构中的 window size 。

零滑窗

当接收方允许接收的片段大小等于 0 时,这意味着接收方的接收能力降为 0 。当发送方得到该通知后,停止发送。如果可以继续接收的时候,接收方会通知发送方恢复发送,然而 ACK 回复不可靠,如果 ACK 回复丢失,那么就会进入死锁状态。所以发送方会不断探测接收方的窗口大小。

白痴窗口

这主要指的是 TCP 通信中,包含的信息很小,流量主要是 TCP 的首部,从而造成了流量的浪费。为此,TCP 规定接收方宣告的窗口必须达到一定的尺寸,否则等待;除了一些特殊情况,发送方发送的片段必须达到一定的尺寸,否则等待。

重新发送

超时重新发送

如果直到计时完成,发送方还是没有收到 ACK 回复,那么发送方推测之前发送的 TCP 片段丢失,因此重新发送之前的 TCP 片段,这个计时等待的时间叫做重新发送超时时间( RTO )。上述过程有两个往返:发送片段从发送方到接收方,ACK 从接收方到发送方。整个过程的实际耗时叫做往返耗时( RTT )。RTO 理想状态应该等于 RTT ,但是 RTT 受到网络的状态影响。所以 RTO 必须符合当前网络的使用状态,网络状况越好,RTO 应该越短。反之,则越长。
TCP 协议通过统计 RTT 来决定合理的 RTO 。发送方测量出每次 RTT ,然后得到 srtt(sampling round trip time)。每次的 srtt 作为采样样本,计算平均值和标准差。得到计算 RTO 的公式:RTO = mean + 4 * std

快速重新发送

TCP 协议可能在计时完成之前启动重新发送,这就是利用快速重新发送。TCP 协议规定,如果接收方收到乱序片段时,需要重新发送 ACK ,比如缺少了序列 8 ,那么接收方就会回复 ACK,回复号为 8 。如果接下里收到的还不是 8 ,则继续重新发送 ACK=8 。发送方收到 3 个 ACK=8 ,就会直接打断即时,直接重新发送片段 8 ,这就是利用了快速重新发送机制。

堵塞控制

TCP 需要保证传输的可靠性,遇到 IP 报文丢失的情况,TCP 就会重新发送 TCP 片段,如果本来是因为堵塞而导致丢失 IP 报文,网络会因为重新发送的 TCP 报文而更加堵塞。当 TCP 的发送方探测到网络交通拥堵时,会控制自己发送片段的速率。TCP 协议其实是通过控制滑窗的大小来控制发送速率,除了 advertised window size 以外,TCP 还会维护一个 congestion window size 。真实的滑窗大小取两个滑窗的最小值。

相关文章