TCP/UDP协议对比分析

TCP与UDP区别:

TCP提供可靠的服务,不丢失,不重复。UDP没有保证。

TCP头部20字节,UDP头部8字节等。

TCP的全称为传输控制协议。这种协议可以提供面向连接的、可靠的、点到点的通信。

UDP全称为用户数据报协议,它可以提供非连接的不可靠的点到多点的通信。

TCP协议详解

TCP头部

主要组成部分:

  • 序列号:在建立连接时由计算机生成的随机数作为其初始值,随机数的生成规则是:每4秒加1的计数器加上hash(源端口+源ip+目的ip+目的端口),保证序列号在4.55小时内是唯一的,通过syn包传递过接收端主机,每发送一次数据就[累加]一次该[数据字节数]的大小。主要用来保证网络包的有序性
  • 应答序列号:指下一次[期望]收到的数据的序列号,一般指应答序列号之前的数据已经确定收到了。主要作用是确保网络包的可靠传输。
  • 控制位

1.SYC:该位为1时,表示希望建立连接,并且进行序列号初始化设置。

2.ACK:该位为1时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。

3.RST:该位为1时,表示TCP连接中出现异常必须强制断开连接。

4.FIN:该位为1时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位置为1的TCP段。

什么是TCP?

TCP是面向连接的、可靠的、基于字节流的传输层通信协议。

  • 面向连接:发送端和接收端建立一个连接通道,为了维护连接的可靠性,通过一定的数据结构来维护双方的交互状态。
  • 可靠性:无论网络链路出现了怎样变化,TCP都可以保证一个报文一定到达接收端。
  • 字节流:发送的时候发的是一个流,没头没尾。所以无论消息有多大都可以进行传输,并且消息是[有序的],通过序列号保证报文的有序性和正确性。

什么是TCP连接?

用于保证可靠性和流量控制维护的一些状态信息,这些信息的组合包括:Socket套接字,序列号和窗口大小。

建立一个TCP连接需要客户端与服务端达成上述三个信息的共识:

  • Socket:由源、目的IP和端口号组成
  • 序列号:用于保证有序性
  • 窗口大小:用于做流量控制

如何确定一个唯一的连接?

通过这四个元素来确定一个唯一的连接,源地址和目标地址存储在IP头部中,源端口和目标端口存储在TCP头部中。

有一个IP的服务端监听了一个端口,它的TCP的最大连接数是多少?

对于ipv4,客户端ip数最多为2的32次方,端口数最多为2的16次方,也就是服务端单机最大TCP连接数约为2的48次方。

不过这个数量只是一个理论上的最大值,实际上服务端会受到文件描述符限制内存限制

  • 文件描述符限制:Socket都是文件,在操作系统层面对应一个fd(文件描述符),所以首先要通过ulimit配置文件描述符的数目
  • 内存限制:每个TCP连接都要占用一定的内存

私信我,领取最新最全C++音视频学习提升资料,内容包括(C/C++LinuxFFmpeg webRTC rtmp hls rtsp ffplay srs

UDP与TCP的区别

什么是UDP协议?

1.UDP是面向无连接的,

2.UDP发送网络包之后,不保证消息不丢失,不保证按顺序达到。

3.UDP是无状态协议,协议头只包含源和目的端口,不会使用特定的数据结构保存客户端和服务端的交互状态。

4.UDP不会进行拥塞控制,进行网络包发送时,不会去根据网络通道的拥塞情况,进行拥塞控制

UDP头部

  • UDP头部固定为64个字节
  • 目标和源端口:标识报文需要发送给哪个进程
  • 包长度:标识了头部和数据的总长度
  • 校验和:校验报文的有效性,为保证可靠性而设计

TCP和UDP的区别

1、连接

  • TCP是面向连接的传输协议,传输数据前需要建立连接
  • UDP不需要建立连接,即刻传输数据

2、服务对象

  • TCP是一对一的两点服务,即一条连接只有两个端点
  • UDP支持一对一、一对多、多对多的交互通信

3、可靠性

  • TCP是可靠交互数据的,数据可以无差错、不丢失、不重复、按需到达。
  • UDP不保证可靠交互数据,可靠性主要依赖于网络环境

4、拥塞控制,流量控制

  • TCP通过流量控制和拥塞控制,保证数据传输的安全性
  • UDP不会去感知传输通道是否阻塞,接收方的接收压力,即使网络拥堵了,也不会自主控制发送速率

5、首部开销

  • TCP首部比UDP大很多,没有使用[选项]字段时是20字节
  • UDP首部长度为8个字节,并且是固定不变的,开销较小

TCP和UDP的主要应用场景

由于TCP是面向连接,能保证数据的可靠传输,因此主要用于:

  • SFTP文件传输
  • http,https

由于UDP面向无连接,数据传输简单高效,但是数据传输不保证安全性和可靠性,因此适用于

  • 包量较小的通信,例如DNS
  • 视频和音频传输
  • 广播通信

TCP连接建立

TCP是面向连接的协议,所以使用TCP之前必须要先建立连接,而建立连接是通过三次握手来进行

三次握手步骤:

1.刚开始时,客户端和服务端都处于closed状态,先是服务端主动去监听某个端口,进入listen状态

2.客户端随机生成一个初始序列号client_isn,将该值放置于TCP首部的[序号]字段,同时把SYN标志位改为1,表示SYN报文。接着把报文发送给服务端,表示向服务端发起连接请求,该报文不包含应用层数据,之后客户端处于SYN-SENT状态。

3.服务端收到SYN请求之后,随机生成一个初始序列号server_isn并放置到[序号]字段中,然后再把收到的SYN请求包的序号字段client_isn+1并将其放置在[确认应答号]中,接着把SYN和ACK标志改为1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD状态。

4.客户端收到服务端的报文后,还要向服务端回应最后一个应答报文,把报文的首部ACK标志为1,[应答序列号]字段填入server_isn+1,把报文发送给服务端。这次报文可以携带客户端发给服务端的数据,之后客户端进入established状态。

TCP为什么采用了三次握手,而不是二次握手呢?

1.两次握手:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方的序列号

客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:

  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:

  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

2.同步双方的初始序列号

客户端和服务端的请求都必须是一来一回,这样才能保证双方的初始序列号是可靠的同步。

SYN攻击

我们都知道 TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的 SYN 接收队列(未连接队列),使得服务器不能为正常用户服务。

解决方案一:

  • 通过调整linux内核参数,调整SYN队列的大小,从而调整SYN连接的可接受数量
net.core.netdev_max_backlog
  • 调整SYN_RCVD状态连接的最大个数:
net.ipv4.tcp_max_syn_backlog
  • 超出处理能力时,对新的SYN直接返回RST,丢弃连接
net.ipv4.tcp_abort_on_overflow

解决方案二:

设置tcp_syncookies,可以应对SYN攻击

net.ipv4.tcp_syncookies = 1
  • 当 「 SYN 队列」满之后,后续服务器收到 SYN 包,不进入「 SYN 队列」;
  • 计算出一个 cookie 值,再以 SYN + ACK 中的「序列号」返回客户端,
  • 服务端接收到客户端的应答报文时,服务器会检查这个 ACK 包的合法性。如果合法,直接放入到「 Accept 队列」。
  • 最后应用通过调用 accpet() socket 接口,从「 Accept 队列」取出的连接。

解决方案三:

通过引入一个中间代理来抵御SYN攻击。

方式一:接收SYN请求和响应SYN-ACK请求都由代理来完成,接收到第三次握手的ACK请求之后,代理与服务端正式建立连接。

方式二:

服务端响应SYN-ACK请求之后,代理立马给服务端发送一个ACK请求,使得SYN队列的请求立马得以释放,代理经过一段时间没有收到客户端的ACK请求,则会向服务端发送RET报文使服务端断开连接。

TCP连接断开

实现过程:

1.客户端打算关闭连接时,对服务端发送一个FIN标志为1的报文,之后客户端进入fin_wait1的状态。

2.服务端接收到该FIN报文后,向客户端返回一个ACK报文,并且进入close_wait状态。

3.客户端收到服务端的ACK答复后,进入FIN_WAIT2状态。

4.等服务端处理完数据之后,主动给客户端发送一个FIN报文,之后服务端进入LAST_ACK状态。

5.客户端收到FIN报文后,回一个ACK应答报文,之后进入TIME_WAIT状态。

6.服务端收到ACK应答报文之后,进入close状态

7.客户端在TIME_WAIT状态等待2MSL时间之后,自动进入CLOSE状态。

从上面过程我们可以知道,客户端和服务端都需要一个FIN和ACK,因此称为四次挥手。

为什么需要四次挥手,不是三次挥手?

1.服务端收到FIN报文时,这时可能还有一些正在处理中的数据没有处理完,所以服务端不能立马进入close状态,只能立马答复客户端,我收到了客户端的关闭请求。

2.当服务端处理完所有的报文数据之后,只有它自己知道具体的处理完的时间点,因此在处理完之后需要它主动通知客户端,现在可以关闭请求了。

为什么TIME_WAIT等待的时间是2MSL?

2MSL代表一个报文在网络中一来一回的最大有效期,使得一些阻塞的网络包在最大有效期内可以被接收到

为什么要有TIME_WAIT状态?

1.防止旧连接的数据包

经过 2MSL 这个时间,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。

2.保证连接正确关闭

TIME-WAIT 作用是等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。服务端在等待了一段时间还没有收到客户端的ACK,会重新发送一个FIN请求,客户端收到FIN请求会再次答复一个ACK报文

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/124405638