TCP和UDP的区别

相同点

都是传输层的协议

不同点

报头内容不同

TCP:

My helpful screenshot

校验和字段的作用:为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。

UDP:

My helpful screenshot

tcp面向连接,udp面向无连接

  • tcp三次握手建立连接,四次回首断开连接
  • 点对点,端对端的连接
  • 全双工(同时发送和接收数据)

  • 支持一对一,一对多,多对一,多对多
  • 不需要三次握手和四次挥手

三次握手:

My helpful screenshot

  • 第一次握手: 客户端向服务器端发送报文,证明客户端的发送能力正常
  • 第二次握手:服务器端接收到报文并向客户端发送报文,证明服务器端的接收能力、发送能力正常
  • 第三次握手:客户端向服务器发送报文,证明客户端的接收能力正常

四次挥手:

My helpful screenshot

为什么需要三次握手?

客户端向服务器端发送的请求报文由于网络等原因滞留,未能发送到服务器端,此时连接请求报文失效,客户端会再次向服务器端发送请求报文,之后与服务器端建立连接,当连接释放后,由于网络通畅了,第一次客户端发送的请求报文又突然到达了服务器端,这条请求报文本该失效了,但此时服务器端误认为客户端又发送了一次连接请求,两次握手建立好连接,此时客户端忽略服务器端发来的确认,也不发送数据,造成不必要的错误和网络资源的浪费。

如果采用三次握手的话,就算那条失效的报文发送到服务器端,服务器端确认并向客户端发送报文,但此时客户端不会发出确认,由于客户端没有确认,由于服务器端没有接收到确认,就会知道客户端没有请求连接。

为什么挥手需要四次?

这是由于TCP的半关闭(half-close)造成的。半关闭是指:TCP提供了连接的一方在结束它的发送后还能接受来自另一端数据的能力。通俗来说,就是不能发送数据,但是还可以接受数据。

当连接处于半关闭状态时,TCP是允许单向传输数据的,也就是说服务器此时仍然可以向客户端发送数据,等服务器不再发送数据时,才会发送FIN报文段,同意现在关闭连接。

数据传输方式不同,tcp基于字节流,udp基于报文流

用户完整的数据包经过tcp层时会进行拆包(分段),限制:MSS,不会保留用户的边界,同时需要处理粘包问题

而udp会保留用户信息的边界,每次收发数据都是完整的报文

粘包和拆包的问题

My helpful screenshot

TCP协议是流式协议;所谓流式协议,即协议的内容是像流水一样的字节流,内容与内容之间没有明确的分界标志,需要认为手动地去给这些协议划分边界。 粘包时:发送方每次写入数据 < 接收方套接字(Socket)缓冲区大小。 拆包时:发送方每次写入数据 > 接收方套接字(Socket)缓冲区大小。

解决方案有四种:

  • 客户端在发送数据包的时候,每个包都固定长度,比如1024个字节大小,如果客户端发送的数据长度不足1024个字节,则通过补充空格的方式补全到指定长度;
  • 客户端在每个包的末尾使用固定的分隔符,例如\r\n,如果一个包被拆分了,则等待下一个包发送过来之后找到其中的\r\n,然后对其拆分后的头部部分与前一个包的剩余部分进行合并,这样就得到了一个完整的包;
  • 将消息分为头部和消息体,在头部中保存有当前整个消息的长度,只有在读取到足够长度的消息之后才算是读到了一个完整的消息;
  • 通过自定义协议进行粘包和拆包的处理。

tcp可靠传输,udp不可靠

tcp三次握手时生成随机的序列号,确保完整接收;有确认应答机制;有滑动窗口机制,实现流量控制,防止包丢失;有拥塞控制机制;有超时重传机制

udp不确认,不重传,不保证消息可以到达,没有序列号所以不保证数据包的交付顺序,不考虑网络环境

为什么需要序列号?

为之后ACK确认报文做铺垫

为什么需要随机序列号?

防止历史连接内容干扰当前的连接

超时重传机制是什么?

原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止。

My helpful screenshot

滑动窗口机制的作用?

TCP 发送一个数据,如果需要收到确认应答,才会发送下一个数据。这样的话就会有个缺点:效率会比较低。为了解决这个问题,TCP 引入了窗口,它是操作系统开辟的一个缓存空间。

发送窗口swnd:

My helpful screenshot

接收窗口rwnd:

My helpful screenshot

滑动窗口的大小实际上是在接收方来定义的,在建立TCP连接时,双方协商并初始化流量控制的参数。其中包括窗口大小(通常是以字节为单位的接收缓冲区大小)和初始的拥塞窗口cwnd大小(swnd=min(cwnd, rwnd))。

拥塞控制机制是什么?

发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度并且动态变化

swnd=cwnd

维护一个慢开始ssthresh状态变量

My helpful screenshot

  • 慢开始
  • 拥塞控制
  • 快重传
  • 快恢复

慢开始:

假设当前发送方拥塞窗口cwnd的值为1,而发送窗口swnd等于拥塞窗口cwnd,因此发送方当前只能发送一个数据报文段,接收方收到该数据报文段后,给发送方回复一个确认报文段,发送方收到该确认报文后,将拥塞窗口的值变为2,之后拥塞窗口大小每次都*2

当cwnd增长到慢开始门限,采用拥塞避免算法

拥塞避免:

每个传输轮次,拥塞窗口cwnd只能线性加一,而不是像慢开始算法时,每个传输轮次,拥塞窗口cwnd按指数增长。同理,16+1……直至到达24,假设24个报文段在传输过程中丢失4个,接收方只收到20个报文段,给发送方依次回复20个确认报文段,一段时间后,丢失的4个报文段的重传计时器超时了,发送发判断可能出现拥塞,更改cwnd和ssthresh.并重新开始慢开始算法

快速重传

接收方收到后,发现这不是按序到达的报文段,会给发送方发送针对n号报文段的重复确认,如果连续收到三次,会在超时重传计时器结束前启动重传

My helpful screenshot

快恢复

My helpful screenshot

在实际的TCP实现中,滑动窗口和拥塞窗口是结合使用的。发送方在发送数据时,受限于两个窗口中的较小值,即发送窗口 = min(滑动窗口, 拥塞窗口)。这确保了数据传输既不会超过接收方的接收能力,也不会导致网络拥塞。