TCP与UDP的区别
UDP协议是面向无连接的,也就是说不需要在正式传递数据之前连接起双方;UDP协议只是数据报文的搬运工,不保证有序且不丢失地传递到对端,具有不可靠性和高效性,适用于实时性要求高的地方;UDP支持一对多,多对多,多对一的传输方式。
TCP在建立连接和断开连接都需要先进行握手,在传输数据的过程中保证可靠性。
TCP头部
Sequence number这个序号保证TCP传输报文的有序性,对端可以通过序号顺序拼接报文;
Acknowledgement number表示接收端希望接收的下一个字节的编号是多少,也表示上一个序号已经收到
Window Size表示还能接收多少字节的数据,用于流量控制。
标识符
- URG=1:该字段为一表示本数据报的数据部分包含紧急信息,是一个高优先级数据报文,此时紧急指针有效。紧急数据一定位于当前数据包数据部分的最前面,紧急指针标明了紧急数据的尾部。
- ACK=1:该字段为一表示确认号字段有效。此外,TCP 还规定在连接建立后传送的所有报文段都必须把 ACK 置为一。
- PSH=1:该字段为一表示接收端应该立即将数据 push 给应用层,而不是等到缓冲区满后再提交。
- RST=1:该字段为一表示当前 TCP 连接出现严重问题,可能需要重新建立 TCP 连接,也可以用于拒绝非法的报文段和拒绝连接请求。
- SYN=1:当SYN=1,ACK=0时,表示当前报文段是一个连接请求报文。当SYN=1,ACK=1时,表示当前报文段是一个同意建立连接的应答报文。
- FIN=1:该字段为一表示此报文段是一个释放连接的请求报文。
建立连接的三次握手
起初,两端都为close状态。双方在开始通讯前都会创建TCB,服务器创建完TCB后便进入listen状态,等待客户端发送数据。
第一次握手
客户端向服务端发送请求报文段,该报文段中包含自身的数据通讯初始序号,发送后,客户端便进入SYN-SENT状态。
第二次握手
服务器接收到SYN后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入SYN-RECEIVED
第三次握手
当客户端接收到同意连接的应答后,还要向服务端发送一个确认报文,发送完进入established状态,服务器收到这个应答也进入established状态,连接建立成功。
为什么不能两次就建立连接?
假设:客户端发送了一个连接请求 A,但是因为网络原因造成了超时,这时 TCP 会启动超时重传的机制再次发送一个连接请求 B。此时请求顺利到达服务端,服务端应答完就建立了请求,然后接收数据后释放了连接。
这时候连接请求 A 在两端关闭后终于抵达了服务端,那么此时服务端会认为客户端又需要建立 TCP 连接,从而应答了该请求并进入 ESTABLISHED 状态。但是客户端其实是 CLOSED 的状态,那么就会导致服务端一直等待,造成资源的浪费。
断开连接时的四次握手
第一次握手
客户端发送完数据,向服务端发送连接释放请求。
第二次握手
服务器接收到FIN后,告诉应用层要释放TCP连接,发送ACK包,进入close-wait状态。此时服务端不再接收客户端数据,但仍旧发送剩余数据给客户端。
第三次握手
服务端发送完毕后会发送连接释放请求给客户端,然后服务端进入last-ack状态。(可以通过延迟机制将二三次握手合并,延迟ack的发送)
第四次握手
客户端接收到释放请求后,向服务端发送确认应答,进入time-wait状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。
TCP延迟机制
- 就像我们合并HTTP请求一样,TCP自身也有一种机制来合并一些ACK反馈消息,这就是延迟ACK机制。
- 当一个数据发送时,发送方一开始并不知道数据是否发送成功,它只能等对方的ACK反馈。当然,在交互过程中一次也不止处理一个数据包,不需要确认前一个包是否已发送就可以发送后面的数据,因为接收方会负责给这些包排序,不用担心顺序问题。而延迟ACK机制就是让接收方在收到数据后不立即反馈ACK消息,而是等到一小段时间,如果之后还有收到其他包就把这些ACK消息一起放入一个包中反馈给客户端。
- 延迟有一个时间限制,通常不会超过200ms。
TCP流量控制
利用滑动窗口实现流量控制
流量控制就是让发送方的发送速率不要太快,使接收方来得及接收。根本目的是防止分组丢失,构成TCP可靠性的一方面。
滑动窗口协议(连续ARQ协议),主要方式是接收方返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送。
由流量控制引发的死锁
当发送者接收到一个窗口为0的应答,便会停止发送,等待接收者的下一个应答。如果这个窗口不为0的应答在传输过程中丢失,发送者会一直等待,而接受方也在等待接收新数据,从而产生死锁。
为了避免死锁,TCP使用了连续计时器。每当发送方接收到一个零窗口应答后就启动。时间一到便主动询问接收者窗口大小。若接收者仍返回0窗口,则重置该计时器继续等待;若不为0,则表示应答报文丢失,此时重置发送窗口后发送。
TCP拥塞控制
拥塞控制是作用于网络的,防止过多的数据拥塞网络,避免出现网络负载过大的情况。
拥塞处理包括了四个算法,分别为:慢开始,拥塞避免,快速重传,快速恢复。
我们开始假定:1、数据是单方向传递,另一个窗口只发送确认;2、接收方的缓存足够大,因此发送方的大小的大小由网络的拥塞程度来决定
慢开始算法
慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
想必大家都下载过资源,每当我们开始下载的时候都会发现下载速度是慢慢提升的,而不是一蹴而就直接拉满带宽。
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:当cwnd<ssthresh时,使用慢开始算法。
当cwnd>ssthresh时,改用拥塞避免算法。
当cwnd=ssthresh时,慢开始与拥塞避免算法任意
拥塞避免算法
拥塞避免算法相比简单点,每过一个往返时间 RTT就把发送方的拥塞窗口加一,而不是加倍,这样能够避免指数级增长导致网络拥塞,慢慢将大小调整到最佳值。
快速重传算法
快速重传一般和快恢复一起出现。一旦接收端收到的报文出现失序的情况,接收端只会回复最后一个顺序正确的报文序号。如果发送端收到三个重复的 ACK,立刻重传对方尚未收到的报文。无需等待重传定时器超时。
快恢复算法
当发送方连续接受到三个重复确认的时候,就执行“乘法减小”算法,将ssthresh减半,此时不执行慢开始,而是拥塞避免,使拥塞窗口缓慢增大。
注意:在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用