我们关键需要掌握传输层的功能,工作方式和原理,需要重点掌握UDP,TCP协议(包括报文分析,首部格式,可靠传输,流量控制,拥塞控制,连接管理)。
传输层是一个介于面向通信和面向用户功能的中间人。
端口:端口是方便知道应用进程的对应标识。TSAP 我们叫做 传输层的服务访问点
数据链路层的SAP 是MAC地址,网络层的SAP 是IP地址,传输层的SAP是端口
应用进程用到了端口号来标识应用进程,端口号长度是16Bit,也就说我们最多能标识65536( 2 16 2^{16} 216)个端口。
我们常用的一些服务会使用熟知服务口:
应用程序 | FTP | Telnet | SMTP | DNS | TFTP | HTTP | SNMP |
---|---|---|---|---|---|---|---|
端口号 | 21 | 23 | 25 | 53 | 69 | 80 | 161 |
套接字 = [主机IP地址,端口号]
当采用TCP的时候,传输层对上提供的是一条可靠的全双工信道
采用UDP的是时候,传输层对上提供的是一条不可靠的信道
TCP:应用在FTP,HTTP,Telnet
UDP:应用在TFTP(小文件传送协议),DNS,SNMP和RTP(实时协议)
IP数据报和UDP数据报的区别:IP数据报在网络层需要进行路由的存储和转发,但是UDP数据报是端对端的,对路由的存储和转发不可见
如果我们的程序选择了UDP协议的话, 我们很大程度上需要直接和IP打交道
UDP数据报首部:
UDP数据报保活两个部分:UDP首部和使用户数据,整个UDP数据报首部8B,四个字段,每个字段占2B(16位)
TCP/IP是一个用来解决可靠,有序,无丢失,不重复的问题。
TCP报文也是分为首部和数据两部分,结构如下:
我们如果用逻辑符号表示一下:
ack表示确认号,大写的ACK表示确认位
连接建立:
【1[CtS]】 S Y N = 1 , s e q = x SYN=1,seq=x SYN=1,seq=x
【2[StC]】 S Y N = 1 , A C K = 1 , s e q = y , a c k = x + 1 SYN=1,ACK=1,seq=y,ack=x+1 SYN=1,ACK=1,seq=y,ack=x+1
【3[CtS]】 A C K = 1 , s e q = x + 1 , a c k = y + 1 ACK=1,seq=x+1,ack=y+1 ACK=1,seq=x+1,ack=y+1
连接释放:
【1[CtS]】 F I N = 1 , s e q = u FIN=1,seq=u FIN=1,seq=u
【2[StC]】 A C K = 1 , s e q = v , a c k = u + 1 ACK=1,seq=v,ack=u+1 ACK=1,seq=v,ack=u+1
【3[StC]】 F I N = 1 , A C K = 1 , s e q = w , a c k = u + 1 FIN=1,ACK=1,seq=w,ack=u+1 FIN=1,ACK=1,seq=w,ack=u+1
【4[CtS]】 A C K = 1 , s e q = u + 1 , a c k = w + 1 ACK=1,seq=u+1,ack=w+1 ACK=1,seq=u+1,ack=w+1
我们知道在IP层的传输可能是不可靠的,我们在TCP实现可靠的方法就是增加校验和重传的机制来保证可靠。
序号机制:
我们给每一个的字节进行编号,一句是我们的发送缓冲区有10个字节,那么我们从0开始编号,假如对面收到了数据之后则会发送ACK确认
什么时候出现重传?
超时和冗余ACK:
所谓的流量控制就是发送方为了协调接收方缓冲区溢出的可能性而进行的操作。
TCP会提供一种滑动窗口机制,在通信当中接收方会根据自己接收的缓存的大小动态调整发送方的发送窗口大小。
我们利用TCP报文里面首部的字段来限制发送方的报文注入速率。
发送窗口的大小由接收窗口和拥塞窗口的最小值决定
我们可以看一个TCP进行流量控制的例子:
我们可以发现,发送端的发送控制权实际上掌握在接收方的手上的。
发送端的窗口大小也是由接收方进行调节的。
流量控制和拥塞控制的区别在于:流量控制是防止发送端和接收端不协调而做的控制,拥塞控制是防止在中途的路由器和交换主机数据拥塞的情况发生。
流量控制是解决是端的问题,拥塞控制解决的是路上的问题。
例子:假如我们的某个链路的传输速率是10Gb/s,我们的一台主机用1Gb/s的速率发文件,那接收端的PC不一定能来得及接收,这个时候就需要流量控制。但现在有100万台主机同时以1Mb/s的速率发文件,这个时候我们就要考虑这个网络负载是否超过了能承受的范围了。
拥塞窗口实际上维护就是了全局的网络拥塞情况。
下面讲解一下怎样进行拥塞控制:
慢开始算法:在TCP刚刚连接好,开始发送TCP报文段的时候先令cwnd = 1(这个我们放在首部的选项字段MSS里面),每收到一个新的报文段的确认之后cwnd+1。
假如A向B发送数据,假如A的拥塞窗口是2的时候,一次可以发送两个TCP的报文段,经过一个传输轮次之后,A收到B对刚才两个报文的确认就会把拥塞窗口调到4,那么下一次发送的时候就能发送4个报文段。
当我们的慢开始算法达到一定的阈值之后,(因为每经过一个传输轮次拥塞窗口就会加倍),我们就开始改用拥塞避免算法。
慢开始算法会使得cwnd的大小是按照指数型的增加的。
拥塞避免算法:每经过一个RTT的话,cwnd就加1,就是无论确认多少ACK都+1,保证这个cwnd是按照线性增长。
如果出现一次超时,就使得变成原来的一半
总的来说就是:加法增加,乘法减少。
一般来说,我们更加倾向于(更加频繁)使用拥塞避免算法,因为指数的增加导致意外的出现更加频繁。
除了慢开始+拥塞避免这样的策略之外,我们还要其他的改进方案吗?
有的,快重传和快恢复就是对拥塞避免算法的改进。
快重传算法:就是之前说过的对于冗余ACK的处理。
快恢复算法:当我们的发送端收到了三个冗余的ACK之后,就执行乘法减少的算法。