传输层:是只有主机才有的层次
传输层为上层应用层提供通信服务,同时使用下层网络层提供的服务。
传输层的功能:
面向连接的传输控制协议TCP:传送数据之前必须建立连接,数据传送结束之后要释放链接,不提供广播或多播服务。由于TCP要提供可靠的面向连接的传输服务,因此不可避免增加了许多开销:确认、流量控制、计时器及连接管理等
可靠,面向连接,时延大,适用于大文件
无连接的用户数据报协议UDP:传送数据之前不需要建立连接,收到UDP报文后也不需要给出任何确认。
不可靠,无连接,时延小,适用于小文件。
复用:应用层所有的应用进程都可以通过传输层再传输到网络层
分用:传输层从网络层收到数据后,交付指明的应用进程
两个主机通信,根据网络层的IP地址寻找到两个主机所在的网络,进入网络之后就要依靠链路层的MAC地址定位到主机,然后再依靠传输层的端口定位到主机中的进程。
端口是传输层的SAP,标识主机中的进程。这个端口叫做逻辑端口/软件端口,这和硬件端口(比如路由器交换机直接可以插上去的端口)不一样,传输层的端口是透明的(看不见摸不着的),所以我们叫它逻辑端口。
每个端口都有一个端口号来标识,端口号只有本地意义,在因特网中不同计算机的相同端口是没有联系的
localhost:8080
很熟悉吧,Tomcat默认端口号8080,两台主机的相同Tomcat端口号是没有关系滴端口号长度为16bit,能表示216 = 65536个不同的端口
端口号按范围分类如下:
服务端指的是服务器端所使用的端口号,客户端指的是主机所使用的端口号。客户端端口号仅在客户进程运行时才动态的选择,通讯结束后,刚用过的客户端口号就不复存在,因此这个端口号就可供其他客户进程以后使用。
一些常用的熟知端口号如下:
我在21岁发现了心仪的女生,23岁我们开始谈恋爱,25岁我们闹矛盾删了好友,53岁我给她打电话,然而她人在异乡,我们相约80岁还要再见。(这什么鬼故事😅)
在网络中采用发送方和接收方的套接字组合来识别端点,套接字唯一标识了网络中的一个主机和它上面的一个进程
套接字Socket = (主机IP地址,端口号)
UDP只在IP数据报服务之上,增加了很少功能:复用分用和差错检测功能
UDP的主要特点:
UDP是无连接的,减少开销和发送数据之间的时延
UDP使用最大努力交付,即不保证可靠交付
UDP是面向报文的,适合一次性传输少量数据的网络应用
UDP无拥塞控制,适合很多实时应用
UDP首部开销小8B,TCP的首部20B
如上图,应用层的应用程序会产生应用层报文,这个应用层报文作为应用层的传输单元向下传递,传递到传输层进行封装,封装成UDP首部和UDP用户数据报数据部分(如果使用TCP协议会封装成TCP的首部),接下来传输层继续向下传递,传输到网络层进行封装,封装成IP首部和IP数据报数据部分。我们说UDP是面向报文的,其实就是在说UDP对于应用层向下传递的报文是既不合并也不拆分的,对这个报文的长度大小是不做任何改变的, 而是保留这些报文的边界,也就是整个应用层的报文都会放到传输层的一个报文段当中,或者说放到UDP的一个数据报当中。
应用层给UDP多长的报文,UDP就照样发送,即一次发一个完整报文
UDP首部格式由8B的首部字段和数据字段组成。
我们看UDP校验的过程,UDP的首部数据前面又加了12B伪首部,伪首部包括字段如上图,为首部只有在计算检验核实才出现,不向下传送也不向上递交。
如上图左左边是发送方准备发送的UDP用户数据报+伪首部进行校验。为首部和UDP数据报结合的整体,我们要将其看成由许多16位的字串连接起来的,也就是一行占4B.
我们来看UDP字段在发送端的过程:
接收端收到UDP字段如何进行UDP校验和校验呢:
TCP是面向连接(虚连接)的传输层协议
每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的
TCP提供可靠交付的服务,无差错,不丢失,不重复,按序到达。(可靠有序,不丢不重)
TCP提供全双工通信:一端既可以作为发送方,也可以作为接收方。所以两端都会设置发送缓存和接收缓存
如上图,假如发送方要发送这样一个文件,它会将这个文件按照字节进行排序并编号,在发送的时候就会将这些字节放入TCP的缓存当中,如上图是将前10个字节放入缓存当中等待发送。可能先取123字节组成TCP报文段,在报文段上加上TCP的头部形成完整报文段,再放到链路上面进行传输。
TCP报文段包括两个部分:TCP首部和TCP数据部分
TCP连接传输要经过三个阶段:建立连接->数据传送->连接释放
TCP连接的建立采用客户服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫服务器。 TCP连接的建立就是三次握手。
假设运行在一台主机(客户)上的进程,想与另一台主机(服务器)上的一个进程建立一条连接,客户应用进程首先通知客户TCP,他想建立一个与服务器上某个进程之间的连接,客户中的TCP会用以下步骤与服务器中的TCP建立一条TCP连接:
客户端发送连接请求报文段,无应用层数据(无数据部分)
服务器端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接,无应用层数据。
客户端为TCP连接分配缓存和变量,并向服务器端返回确认的确认,可以携带数据。
SYN洪泛攻击发生在OSI第四层,这种方式利用TCP协议的特性就是三次握手。攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包, 而当服务器返回ACK后,该攻击者就不对其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送ACK给攻击者。这样更加会浪费服务器的资源,攻击者就对服务器发送大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上这些TCP连接会因为挂起状态来消耗CPU和内存,最后服务器可能死机就无法为正常用户提供服务。
四次握手:男生说完话之后说一句"我说完了",女生开始说"好的,我想说的是巴拉巴拉",说完话后再说一句"我说完了",男生说"好吧"。(好尴尬哈哈)
参与一条TCP连接的两个进程中的任何一个都能终止该连接,连接结束后,主机中的资源(缓存和变量)将被释放
TCP释放连接的过程:
网络层是提供尽最大努力交付,不可靠传输。传输层使用TCP实现可靠传输。
TCP实现可靠传输的机制:
校验:与UDP协议校验一样,都是增加伪首部,通过计算二进制反码求和的方法来校验
将数据按照字节进行排序并编号,一个字节占一个序号,序号字段指的是一个报文段第一个字节的序号。(上方有记录序号字段)
如上图发送方的TCP缓存中有10个字节的报文段,发送方首先发送123字节所构成的报文段,发送成功后,接收方就将其存储在TCP缓存当中,并找合适的时间将TCP缓存中的报文段提交给应用层。但是发送方的TCP缓存中仍然存有123字节所构成的报文段,因为有可能网络不畅,接收方需要发送方重新再传一次数据,所以发送方需要一直存有这个报文端,直到接收端告诉发送端"OK,I get it",然后发送端才可以把这个报文段丢失。
发送方如何知道接收方接收了这个报文段呢?就是要靠确认机制,接收方收到报文段之后会返回一个确认报文段,这个报文段是在合适的时候发生了确认,TCP默认使用累计确认,这个确认报文段首部确认号字段就是4。当然接收端也可以在发送数据的时候把这个确认报文段捎带上,叫做捎带确认。
如果发送方发送456、78组成的报文段,由于网络原因只发送了78报文段,456报文段扔在了链路上,虽然接收方收到了78字节的报文段,但是由于456字节的报文段还没有到,所以接收方返回的确认报文段的首部确认号字段仍然为4,告诉发送方我需要的是以4开头的报文段。这样接收方收到确认报文段之后,就会知道456字段还没有到达,所以重新发送456。
确认和重传不分家,TCP的发送方在规定的时间内没有收到确认,就要重传已发送的报文(超时重传)
有两种事件会导致TCP对报文段进行重传:超时和冗余ACK
TCP采用自适应算法,动态改变重传时间RTTs(加权平均往返时间)
超时触发重传存在的一个问题是超时周期往往太长,有没有一种办法可以在超时时间之前就能知道这个报文段没有发送成功呢?
发送方收到3个对于报文1的冗余ACK -> 认为二报文段丢失,重传2号报文段(快速重传)
流量控制:让发送方慢点,要让接收方来得及接收
TCP利用滑动窗口机制实现流量控制。在通信过程中,接收方根据自己接收缓存的大小动态的调整发送方的发送窗口大小,即有一个接收窗口rwnd(接收方通过设置确认报文段的窗口字段来自rwnd通知给发送方,相当于告诉发送方我现在可以接收的最大字段是多少),发送方根据接收到的消息就会调整发送窗口的大小:发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值
假如A主机向B主机发送数据,TCP连接建立时, B主机告诉A主机:接收方的接收窗口rwnd=400B,设每个报文段100B,报文段序号初始值为1,如上图:
接着A给B再发送一个报文段,序号从101开始,长度为100B,这样A还能再发送200B
接着A给B再发送一个报文段,序号从201开始,长度为100B,但是发送过程中丢失了
接着B返回给A一个确认报文段:确认位ACK=1表示确认号有效,确认号ack=201,表示期望收到发送方发送的字节序号是201,同时将接收窗口rwnd设置为300B
接着A给B再发送一个报文段,序号从301开始,长度为100B,这样A还能再发送100B(由于接受风还没有收到201-300的报文段,所以滑动窗口依然保留201-300报文段)
接着A给B再发送一个报文段,序号从401开始,长度为100B,这样滑动窗口就已经发送完,不能再发送新数据了,因为没有收到接收方的确认,所以等待接收方的确认
201-300的报文段超时重传,所以发送方A接着发送201-300的报文段,因为发送窗口并没有扩大,所以其他数据依然不能发送
接收方返回给A一个确认报文段:允许A发送501-600的报文段(确认号为501,表示501号之前的全部报文段已经收到)
TCP为每一个连接设有一个持续计时器,只要TCP连接的一方收到对方的rwnd零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段,接收方收到探测报文段时给出现在的窗口值。如果窗口仍然是0,那么发送方就重新设置持续计时器。
出现拥塞的条件,对资源需求的总和大于可用资源:网络中有许多资源同时呈现供应不足就会使得网络的性能变坏,网络的吞吐量将随输入负荷增大而下降。
拥塞控制:防止过多的数据注入到网络中。全局性(网络拥塞了,肯定是多个主机同时访问网络上的资源了,所以网络才会拥塞)
拥塞控制和流量控制区别:
- 如下边的左图是拥塞控制,多个发送方给接收方发送数据,同时使用这个网络资源就会拥塞,接收方并不知道是哪一台主机或哪几台主机发送数据过快或过多造成的
- 如下边右图是流量控制:接收方发送过快导致接收方来不及接收
慢开始+拥塞避免,快重传+快恢复
我们假定:
如上图,横坐标是传输轮次,纵坐标是拥塞窗口cwnd:
初始拥塞窗口cwnd=1,1表示一个最大报文段的长度MSS
随着传输轮次的增加,我们的拥塞窗口会发生变化,变到几就代表发送窗口是几
一个传输轮次:指的是发送了一批报文段并收到它们的确认的时间
一个往返时延RTT:开始发送一批拥塞窗口内的报文段到开始发送下一批拥塞窗口内的报文段的时间。
传输轮次 = 往返时延
在最开始拥塞窗口是指数规律增长,我们之所以说它是慢开始,是因为起始的发送报文段是一个报文段,相较于一开始注入很多个报文段来说它就是慢开始,其实就是对这个网络进行探查,先放一个报文段进去,看这个网络情况怎么样,网络情况比较好,那我就再多放几个报文段。
在第4个传输轮次,ssthresh的初始值为16,ssthresh代表慢开始沦陷,就是到了这个初始值,注入报文段速度就要减小,由慢开始进入到拥塞避免,每个传输轮次只增加1个报文段,当拥塞窗口为24时发生了网络拥塞,所以拥塞窗口瞬间直接从24减少到1同时建立新的慢开始沦陷值24/2=12,又进入到慢开始阶段,然后继续指数规律增长,不同的是慢开始沦陷ssthresh的值变为24的一半为12
快重传:收到三个重复的确认(冗余ACK)就执行快重传算法
如上图,快重传之后立马进行快恢复,刚才是只要发生了拥塞立马将拥塞窗口变为1,快恢复是只要发生了拥塞就将拥塞窗口下调为新的沦陷值ssthresh = 12。之后进行加法增大(拥塞避免)