摘要:本节主要介绍了运输层的两个重要协议TCP协议和UDP协议。在UDP协议中,描述了其能提供的基本服务:多路复用和多路分解。在TCP协议中,介绍了其提供可靠数据传输的机制及其流量控制和拥塞控制。
关键词:多路复用;多路分解;TCP;UDP;流量控制;拥塞控制
目录:
1.多路复用和多路分解
2.UDP协议
2.1UDP协议报文段结构
2.2UDP协议的检验和
3.TCP协议
3.1TCP报文段结构
3.2TCP连接与断开过程
3.3可靠数据传输原理
3.4流量控制
3.5拥塞控制
3.6公平性
扩展:TCP拥塞控制算法综述
1 多路复用与多路分解
运输层可以提供很多服务,但他却并不这样做,因为一个层提供太多的服务势必会使得其非常复杂,实现起来也很困难。多路复用与多路分解是运输层提供的最基本的服务。主机要发送数据出去,他只有一个出口,想要接收数据也只有一个入口,但主机上的应用程序却很多,大家都想要发送数据,是不是得等一个应用程序的数据发完了,再发第二个,这样做缺点太多,大家随便都能说上一二,因此怎么做呢,大家都并发的发送报文段,然后排在门口等着发出去,这样在一段时间内,大家都有数据发送(多路复用),响应的入口也有不同应用程序要接收的数据流入,然后分发至各个应用程序(多路分解)。说白了就是应用层的管道技术。
多路复用和多路分解在应用成是怎么执行的呢?很简单,就是给数据报文加上应用程序的标识:源/目的端口号和源/目的ip地址。传输层更具该标识送给对应的应用程序TCP连接子线程。该线程会将数据送回给对应的应用程序。
我们在此处所讲的多路复用与多路分解技术,是针对传输层的,也即是多个TCP连接并发在一个网卡上输入输出时候的情况。
如果多个http连接在一个TCP连接上并发(也即第二章提高的管道化连接,不常用),与此处提到的多路复用与多路分解是不是有异曲同工之妙,其实他也叫多路复用和多路分解技术,只是叫应用层的多路复用与多路分解,而且,更进一步的他是只有多路复用而没有多路分解,也就是http可以并发的发送,但是不会并发的返回,服务器只会顺序的返回响应。
本章此后谈到的技术都是针对单个连接而言,即对传输层的子线程而言。
2 UDP协议
UDP协议就是只提供传输层最基本服务的协议,当然他比多路分解和多路复用服务稍微还多了一点服务,就是差错检测。
UDP是个极为简单的协议,工作原理很直接,发送方只管发数据,至于数据是否在沿途发生了丢失,他也不管,实际上他也不知道,因为没有反馈信息。所以他就只需要不停的发送就可以了。然后接收到下信息也不管顺序,有么有丢失,有多少是多少一股脑发给应用层。
2.1 UDP报文结构
这些字段都是自解释的,除了下节要讲的检验和字段(Checkpoint)
2.2 UDP检验和
UDP检验和就是那个比最基本服务多出来的那一点服务,他主要保证,虽然数据我不一定都收到了,但是争取保证收到的都是正确的无损的。
检验和也很简单,报文在传输都是二进制流,一个字节八位,把所有的字节两个一组也就是16bit,加起来,如果溢出就回卷,知道什么是回卷吗?就是把溢出的那一位当成1,与结果又做一次加法操作。然后把最终结果取反码以此作为检验和,然后在接收方,把他们和检验和加一遍,如果没错,就得到全1的结果,如果有零就说明发生了差错。
3 TCP协议
TCP协议提供可靠信息传输。UDP能提供的他都有,此外他保证帮你把数据都按序无损的传到对方手里。这种可靠运输靠什么来实现呢?显然必须要双方不停的反馈来实现,因此其报文结构和运行机制相比而言要更复杂。
3.1 TCP报文结构
源和目的端口,主要用于多路复用和多路分解。
而序号和确认好则是最关键的保证可靠传输的两个字段,也就是双方的反馈信息,把报文看出一个数组,每个元素一个字节,由于报文在传输层会被分割成报文段,每段会有不同的索引范围。序号和确认号的概念是:
序号:该报文段第一个字节在数组中的索引。
确认号:按理来说应该表明,我已经收到了某段字节,因此把该段的最后一个字节的索引发送出去,正好与序号对应一个是该第一个字节的索引,另一个是最后一个字节的索引,但实际上不是的,他是表示最后一个字节的下一个字节的索引。也就是他表明他期望对方下一次发给他的是哪一段报文。这其实就隐含的确认了,我已经收到上一段报文了。
其中的其他字段,在后面需要用到的时候逐一说明。
3.2 TCP的连接与断开
TCP与UDP不同,TCP是面向连接的,也就是你实现必须要建立起连接,才能开始后续的数据传输。TCP的连接与断开就是常说的TCP三次握手和四次挥手。
TCP是有很多状态的,比如连接建立状态或拆除状态,他们都会用TCP首部中的标志字段进行状态标志。在TCP协议中,往往都使用有限状态机来描述TCP在各个状态之间的转变。例如在拥塞控制时,将使用一张图来描述整个拥塞控制机制。
- TCP三次握手:客户端发送标志为[SYN]报文到服务器,服务器回送[ACK,SYN]标志的报文,客户端发送[ACK]的报文响应。三次握手的过程中,主要是双方确认好初始的序列号。
为什么是三次握手,因为握手成功之后,服务器就要为你开启资源,假如是两次握手,攻击者只要发送SYN报文,服务器收到后发回报文,然后为该连接分配资源,攻击者并不要理会该响应报文,服务器就已经分配了资源,假如攻击者通过伪造源ip地址,发送大量具有不同源ip地址的的SYN报文,服务器资源就被这些攻击者占用了,而无法为正常的客户分配资源。而三次握手不同,他要求客户还要响应一次,服务器拿到客户的响应才会给客户端分配资源。
你又会想,攻击者也响应一次不就可以了吗?是的,确实可以。由于攻击者ip是伪造的,服务器发送的响应,他并收不到,但是没关系,他再用这个伪造的ip发一个[ACK]响应给你服务器就可以了,即使他每收到,而服务器仍然会以为他收到了。所以服务器出了个对策,我给你的序号是利用你给我发的ip地址和源端口号作为输入,利用复杂的加密算法加密得到的,你要在这个加密的序号值上加1,我这边验证通过了,我才会给你开启资源,否则我会认为你是非法用户,攻击者ip是伪造的,他怎么可能知道序号是多少。这样他就不能正确响应了。事实上你可以随机生成你的序号,攻击者都不知道该序号是多少,但是这样有个缺陷,就是服务器自己也得记住这个随机数,以便于对比,这样还是会占用内存。而使用函数就不一样了,来了响应报文又用你的端口和ip算一下,就知道我自己的序号了,这样自己就不用记忆,也就不占用任何资源了。这就是SYN洪泛攻击防御系统:SYN cookie。那串序号就是cookie。
- TCP四次挥手。挥手用于结束连接。用[FIN]标识。四次挥手要分两种情况。
1. 服务器发送[FIN]标识他要传输的数据完毕了,客户发送确认。这个时候连接并没有断开,服务器会在每个响应结束后发送[FIN]标志,客户发送确认后,如果是持续连接,客户端程序往往不会自动再发送[FIN]表示他要结束,因为这个TCP连接还可以继续其他请求,比如你刷新页面,或者请求做其他操作,那客户什么时候才会发送剩下的[FIN]呢,当然就是浏览器关闭的时候。如果你是非持续连接,反正你后面也不能再用这个TCP连接了,客户端程序会自动发送[FIN],然后服务器响应你,这样就结束连接了。
2.我们看到,如果是服务器先发的[FIN]客户端会由于连续性质的不同,而进行不同的响应,是立刻关闭,还是保持半连接。但如果是客户端最先发起的关闭连接,那不管你什么类型的连接,服务器都认为你要断开连接了(他确实有理由这样认为),事实上如果客户端先发[FIN],服务器会直接把[ACK]和[FIN]一次性发给你,然后你再回应一个ACK就可以了。
为什么需要四次挥手呢?主要是为了双方都正常的关闭
什么时候可以双方都关闭,自然是双方都没有要发送数据的时候就关闭。但凡有一方还有数据要发送都不能关闭,也就是双方能否关闭不是你想关闭就关闭,而要取决于对方是否让你关闭,决定权在对方手里。A向B请求关闭,B同意了A也不能关闭,因为B的命运还在A手里,A关闭了谁决定B的死活。这种似乎陷入了一个死循环。因此,请求关闭者必须先给被请求者也发送了关闭请求之后,他才能关闭。比须要四次挥手。四次挥手如果失败,会采取超时等待策略。
3.3可靠数据传输机制
3.3.1重传
为了保证可靠数据的传输,首先要有的功能就是重传。
- 超时重传:超时重传显然就是超过一段时间后,对方没有给我确认,就会重传该报文段。那多久才算超时呢,一般会统计正常的往返时间,然后使用经验公式计算超时间隔
- 快速重传:除了超时重传外,如果对方不停的给我说他需要某一个分组超过三次,就会立刻重传该分组。
3.3.2退回N步&选择重传
退回N步和选择重传都是用于保证数据的可靠传输的,具体细节可以看这个java动画可以有很好的具体形象的认识(可能需要VPN):Go-Back-N和Selective-Repeat,TCP没有单独使用上述两种可靠传输机制,而是综合起来,属于GBN和SR的混合体。我们不在此处描述他们的细节,你只需要直到,他们确实可以保证你的数据按序到达目的到达。
3.4 流量控制
流量控制是为了在接收方能够有足够的缓冲接收来及发送的数据。如果发送方发送的数据太快,就会造成接收方缓冲区溢出。所以通常接收方会发送一个窗口数据告诉发送方下次能发送的最大窗口是多大,该窗口就是在报文首部中的窗口字段标识。
3.5 拥塞控制
拥塞控制是为了有太多的流量挤入网络,导致网络拥塞。因此发送方应该要控制发送的窗口大小,以免发送太多的流量导致网络拥塞。发送方通过超时或者达到多个相同的ACK来判断网络是否拥挤,从而采取响应的策略。
至于采取何种策略,就演化出了不同版本的TCP拥塞控制算法。
书上主要介绍了Reno拥塞控制算法。
Reno拥塞控制算法主要包括慢启动阶段、拥塞避免阶段、快速恢复阶段,该三个状态通过有限状态机表示如下:
其中如果不包含快速恢复阶段那么就变成了Tahoe拥塞控制算法了.
拥塞控制算法有不同的实现方式,主要有Tahoe、Reno、Vegas、CUBIC、BBR等很多,如果负责操作系统网络开发模块的,也许你需要实现一个拥塞控制算法,或者发明一个。如果你不是,那你只需要了解不同的控制算法各自有什么适用场景,然后根据你的网络环境选择适合你的拥塞控制算法。比如如果你搭建了VPN你可以在服务器上选择BBR拥塞控制算法加速。
不管是流量控制还是拥塞控制算法是针对发送方而言的,与接收方没有任何关系,这也就是说,你的机器使用什么拥塞控制算法不影响你接收数据,只影响你发送数据,所以你在代理服务器上开启了BBR算法,不代表你要在客户端也开启BBR,因为你用代理服务器主要还是从国外的网站接收数据,然后代理服务器发给你。所以你的客户端主要是接收数据,与使用何种拥塞控制没有关系。而代理服务器既要接收也要发送,所以他选择何种拥塞控制算法对你而言很重要。
为什么要使用流量控制和拥塞控制?
像UDP那样肆无忌惮的发送数据多好,没有发送窗口的限制。这是不行的,因为TCP他保证了可靠数据传输,如果大家都发送大量的分组出去,大家的分组很多都要超时,超时就要重传,重传就是一种无畏的浪费。从而使得网络的带宽不能有效的利用,而在不停的重传分组。
3.6 公平性
使用拥塞控制算法能保证公平性吗?
通常不能,往往谁的数据多,谁就能抢到更多的带宽,两个人数据一样多的时候谁延迟小谁能抢到更多的带宽。因此要保证公平性只能在路由器设置大家的带宽上限,强制公平性。
如果你是与UDP竞争,那TCP毫无优势。
扩展:TCP 拥塞控制算法综述
[1]Afanasyev A, Tilley N, Reiher P, et al. Host-to-host congestion control for TCP[J]. IEEE Communications surveys & tutorials, 2010, 12(3): 304-342.
[2]曹涛涛. 拥塞控制算法的性能评估及公平性分析[D].南京大学,2017.