关于TCP和UDP协议的一些总结

本文深入解析TCP和UDP的特性与区别,包括TCP的可靠性和UDP的不可靠性,以及TCP的三次握手、四次挥手过程,揭示了半关闭状态、TIME_WAIT状态的意义,探讨了孤儿连接、半打开连接的问题,并介绍了TCP的可靠性保障机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、TCP和UDP的区别是什么?

大体来讲TCP是面向连接的,可靠的字节流服务,UDP是无连接、不可靠的数据报服务。

具体如下图所示:

2、字节流服务和数据报服务的区别是什么?

关于两者的区别,对应到实际编程中,主要体现在通信双方是否必须执行相同次数的读写操作。TCP协议是字节流服务,发送端发送的数据并不是直接发送到接收端,而是先发送到TCP的发送缓冲区中,发送端将数据放在发送缓冲区后就完成写操作了。至于数据什么时候发送取决于TCP协议栈。当TCP模块真正开始发送数据的时候,可能将缓冲区中的数据分成若干个TCP报文段发出,(至于分成几个TCP报文段取决于发送缓冲区的大小和MSS限制)。这说明写的次数和发送的TCP报文段的个数并没有直接关系。从TCP的发送缓冲区发送的报文段并不是直接被接收端接收,而是发送到TCP的接收缓冲区且按照序号进行排列,并告知接收端从接收缓冲区中接收数据,接收端可以一次性获取全部数据,也可以分多次取出,却决于接收端所指定的应用程序读缓冲区的大小,这说明应用程序读的次数和接收缓冲区接收到的TCP报文段的个数没有直接关系。综上所述,字节流的概念就是发送端执行的写操作数和接收端执行的读操作数之间没有任何关系。UDP协议是数据包服务,发送端一次性发送一个数据报,并且不能将其进行拆分,将其封装为UDP数据报直接将其发送到接收端,接收端必须及时对发送来的数据包进行接收,否则会出现丢包。除此之外,接收端应用程序必须保证足够大的缓冲区,否则数据包将会被截断,造成数据的丢失。

3、TCP的半关闭状态是什么?

通信双方中,主动关闭连接的一方会先向另一方发送一个FIN结束报文段,表示自己没有数据要进行发送了,但是却不代表他不能接收数据。TCP的半关闭状态就是指一方主动发送结束报文段后,但是没有收到对方的结束报文段,此时的连接并未真正关闭,它还可以收到对方发送来的数据,这种情况下称之为TCP的半关闭状态。

4、ESTABLISHED状态是什么意思?

当客户端向服务器端主动发起连接时会首先发送一个同步报文段,在其收到服务器端对其进行确认后就会使自己出于ESTABLISHED状态,而服务器发送同步报文段后并且收到了客户端的确认后,自己也就出于ESTABLISHED状态。很明显通信双方经历了TCP的连接建立过程(三次握手)均成为ESTABLISHED状态,它表明了通信双发可以正常的进行双向数据传输的状态。

5、connect()系统调用可能会出现什么问题?

我们知道connect()系统调用是客户端层次的API接口,该系统调用也是标志着连接的开始。正常情况下服务器端程序通过accept()系统调用接受客户端的连接,此时客户端出于ESTABLISHED状态,于是进行正常的数据传输。但是客户端可能连接的是一个未被监听的端口或者该端口仍出于TIME_WAIT状态,那么服务器端会给客户端发送一个RST复位报文端,告知客户端关闭连接或者重新进行连接。或者该端口存在,但是connect()在超时时间内没有收到服务器的确认报文段,那么该系统调用失败,客户端重新成为CLOSED状态。

6、FIN_WAIT_1状态和FIN_WAIT_2状态有什么不同?

当客户端主动发送FIN结束报文段后,客户端就进入了FIN_WAIT_1状态,在收到服务器端的应答确认后,客户端就进入了FIN_WAIT_2状态,此时服务器端出于CLOSE_WAIT状态,当服务器端给客户端发送一个FIN结束报文段后,客户端给与确认并进入了CLOSED_WAIT状态,可以看出FIN_WAIT_1状态是FIN_WAIT_2状态在服务器端对客户端发送的结束报文段进行确认前的一个状态,在确认后到达FIN_WAIT_2状态并在成为TIME_WAIT状态。而FIN_WAIT_1状态可以不通过FIN_WAIT_2状态直接进入TIME_WAIT状态,主要就在于客户端先收到结束报文段,而不是对客户端结束报文端的确认,那么此时直接从FIN_WAIT_1直接进入到TIME_WAIT状态。

7、TIME_WAIT状态存在的意义?

<1>可靠的终止TCP连接;

<2>保证迟来的TCP报文段有足够的时间被识别或被丢弃。

当服务器端向客户端发送FIN结束报文段,客户端向服务器发送结束连接前最后一次确认报文段,但如果说此确认报文段丢失或者滞留在网络中,那么服务器端超时后会继续发送FIN结束报文段,如果客户端不出于TIME_WAIT状态,而是直接结束连接处于CLOSED状态,此时客户端会向服务器端发送一个RST复位报文段,此时对于连接的释放将会产生错误,因此设置TIME_WAIT状态保证了TCP连接可靠的终止。

我们知道一个TCP端口不能被打开多次,当一个TCP连接处于TIME_WAIT状态的时候,不能立即对其端口进行访问而建立一个新连接,需等到2MSL后才能进行访问。假设没有这个状态的存在,当客户端向服务器主动发送结束报文端后,就直接关闭了,此时服务器端可能向客户端还有数据传输,那么新建立的连接由于和旧连接有相同的IP地址和端口号,那么服务器可能将此时的客户端当成旧连接时的客户端,客户端可能收到原来连接中传输的数据,这显然是错误的。

8、什么是孤儿连接?

客户端向服务器端主动发送FIN结束报文段后自己处于FIN_WAIT_1状态,在收到服务器发送的确认报文段后就处于FIN_WAIT_2,假设服务器端一直不发送FIN结束报文段(服务器端异常关闭),那么此时客户端会由内核接管,此时的连接便称之为孤儿连接,客户端就会持续处于FIN_WAIT_1状态而不会进入TIME_WAIT状态。为了防止孤儿连接长时间滞留在内核中,对孤儿连接的数量以及生存时间进行了限制,最终由内核释放孤儿连接。

9、什么情况下通信的一方会发送一个RST复位报文端?

<1>访问一个不存在的端口,这个我们前面以及提到过;

<2>终止一个异常连接,前面我们说过当客户端发送完FIN结束报文段后,就被异常关闭了,此时会向服务器发送一个RST复位报文段;

<3>处理半打开连接;关于什么是半打开连接,请看下面介绍:

10、半打开连接是什么?如何解决?

服务器(或客户端)关闭或者异常终止了连接,而没有收到对方发送的结束报文段,此时客户端(或服务器)还维持着原来的连接,而此时服务器(或客户端即使重启),也已经没有该连接的任何信息了,我们将这种状态称为半打开状态,处于这种状态的连接称为半打开连接。如果服务器(或客户端)往处于半打开状态的连接中写入数据,则会收到对方的RST复位报文段。

11、TCP的三次握手与四次挥手过程是什么?

三次握手:

最初服务器和客户端都为 CLOSED 状态。在通信开始前,双方创建各自的传输控制块(TCB)。
服务器创建完 TCB 后便进入 LISTEN 状态,此时准备接收客户端发来的连接请求。

  • 第一次握手:服务器 B 处于 监听(LISTEN) 状态,此时客户端 A 向 B 发送请求连接报文段。该报文段中 SYN = 1,ACK = 0,seq = x,A 进入 同步已发送(SYN-SENT) 状态,等待服务器确认;(A 问 B 你可以吗?)【ps:SYN = 1,ACK = 0 表示该报文段为请求连接报文;seq = x,x 为本次 TCP 通信的字节流的初始序号,TCP 规定 SYN=1 的报文段不能有数据部分,但要消耗掉一个序号】
  • 第二次握手:服务器 B 收到 A 的连接请求报文段,如果同意建立连接,则向 A 发送连接确认:SYN = 1,ACK = 1,seq = y,ack = x + 1,进入 同步已收到(SYN-RCVD) 状态;(B 告诉 A 我可以)【ps:SYN = 1,ACK = 1 表示该报文段为连接同意的应答报文;seq = y 表示服务端作为发送者时,发送字节流的初始序号;ack = x+1 表示服务端希望下一个数据报发送序号从 x+1 开始的字节】
  • 第三次握手:客户端 A 收到 B 同意连接的应答后,再向 B 发送一次确认报文段,该报文段头部为:ACK = 1,seq = x+1,ack = y+1,客户端发送完这个确认报文后就进入 已建立连接(ESTABLISHED) 状态(A 再告诉 B 我也可以)
  • B 收到 A 的确认后,B 也进入 已建立连接(ESTABLISHED) 状态,完成三次握手

四次挥手:

 

  • 第一次挥手:客户端 A 发送连接释放请求,并停止发送数据,该请求只有报文头,主要参数:FIN = 1,seq = u。此时客户端进入 终止等待1(FIN-WAIT-1) 状态;【FIN=1 表示该报文段是一个连接释放请求,seq = u,u-1 是 A 向 B 发送的最后一个字节的序号】
  • 第二次挥手:服务器 B 收到 A 的释放请求后发出确认,确认报文包括:ACK = 1,seq = v,ack = u + 1。此时 TCP 处于半关闭状态,服务器进入 关闭等待(CLOSE-WAIT) 状态,B 能向 A 发数据但 A 不会向 B 发数据。此时 A 进入 终止等待2(FIN-WAIT-2) 状态,等待 B 传输最后的数据并发送连接释放请求。第二次挥手完成后,A 到 B 方向的连接已经释放,B 不会再接收数据,A 也不会再发送数据。但 B 到 A 方向的连接仍然存在,B 可以继续向 A 发送数据。【ACK=1:除TCP连接请求报文段以外,TCP通信过程中所有数据报的ACK都为1,表示应答;seq=v,v-1是B向A发送的最后一个字节的序号;ack = u+1 表示希望收到从第 u+1 个字节开始的报文段,并且已经成功接收了前 u 个字节】
  • 第三次挥手:当 B 不再需要连接时,向 A 发送连接释放请求,请求头:FIN = 1,ACK = 1,seq = w,ack = u + 1,此时 B 进入 最后确认(LAST-ACK) 状态,等待 A 的确认
  • 第四次挥手:A 收到 B 的请求释放后进行确认,ACK = 1,ack = w + 1,B 进入 CLOSED 状态,A 进入 TIME-WAIT 状态,等待 2 MSL(Maximum Segment Lifetime,最大报文存活时间)若没有收到 B 的重发请求的话,就释放连接并进入 CLOSED 状态。

12、进行两次握手可以吗?

不可以。试想当第一次握手过程,客户端给服务器发送的同步报文段如果因为某种原因滞留在网络中,服务器在超时时间内没有收到客户端的报文段,那么客户端会重传一个同步报文段,服务器收到第二个报文段后,连接建立,但是在一个报文段到达之前,该连接已经断开了,此时网络中滞留的报文段达到服务器,此时服务器会认识这是客户端发送来的新连接,服务器会接受这个连接,并向服务器发送同步报文段,客户端收到该报文段后由于他并没有主动发起连接,所以不会理睬这个连接,客户端并不会向服务器发送新的数据,服务器便开始死等,消耗了系统的资源,但是如果时三次握手,当客户端收到服务器发送的报文段后,不会对其进行确认,那么服务器端收不到客户端的答复,变知道这是个无效的连接,从而释放该链接,而不是傻傻的死等客户端发送数据过来。

13、进行三次挥手可以吗?

可以的,前面我们提到过,客户端可以直接从FIN_WAIT_1进入到TIME_WAIT状态,只不过是收到了服务器端的发送的FIN结束报文端,由于结束报文段中包含了对客户端向服务器发起FIN结束报文段的确认信息,所以第一次单独的确认报文段可以省略,因此可以进行三次挥手。

14、为什么是三次握手?为什么是四次挥手?

三次挥手的原因是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误

四次挥手的原因是 TCP 连接是全双工的,每个方向都必须单独地进行关闭,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接关闭连接时,当 B 端收到 A 端的 FIN 报文通知时,仅仅表示 A 端没有数据发给 B 了,但未必 B 的数据也已经都发给 A 了,所以 B 不会立马关闭 Socket,当 B 发送完自己想发的全部数据后,再发送 FIN 给 A 表示 B 也同样没有数据给对方了。针对每一个 FIN 报文,都需要一个 ACK,所以需要四次挥手。

15、为什么连接的时候是三次握手,关闭的时候却是四次握手?

答: 主要在于 同步 和 应答 是否能同时发送,其实握手也是四次,只不过由于同步和应答合成了一次握手,所以才是三次握手。建立连接时,当服务端收到客户端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但关闭连接时,当服务端收到 FIN 报文时,很可能并不会立即关闭 Socket,所以只能先回复一个 ACK 报文,告诉 Client 端," 你发的 FIN 报文我收到了,但只有我 Server 端所有的报文都发送完了,我才能发送 FIN 报文 "。因此不能一起发送。故需要四步握手。

16、TCP是可靠的传输协议,其可靠之处是如何保证的?

TCP的可靠性表现在:它向应用层提供的数据是无差错的、有序的、无丢失的,简单的说就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的。TCP 可靠性的实现机制:面向连接、确认应答机制、超时重传、流量控制、拥塞控制。

  1. 确认应答:TCP 对数据进行编号(seq),通过确认号(ack)告诉发送者已经收到的数据,且我希望下一个数据从哪里开始发送。
  2. 超时重传:如果发端超过一定时间未收到接收端的应答,可以认为是数据包丢失或应答丢失,此时发端会重发数据,这个时间一般是 2RTT+偏差值(RRT,报文段往返时间)。TCP 采用了自适应算法来确认超时重传时间(记录一个报文发出时间以及收到确认的时间,两者之差即为报文往返时间 RRT)。
  3. 流量控制:流量控制就是让发送方别发太快,让接收端来得及接收。主机间传数据实际是放在缓冲区的,接收端会把自己当前可用缓冲区大小放在 TCP 报文头中的 “窗口大小字段”,在应答(ACK)时通知发送端当前可接收大小。如果接收缓存区满了,就会将窗口设置为 0,这时发送方不再发送数据,但需要定期发送一个窗口探测数据段,让接收端把当前窗口大小告诉发送端。
  4. 拥塞控制:慢启动 + 拥塞避免,快重传、快恢复。

17、UDP是不可靠的传输协议,对其如何进行改善,可以使其变成可靠的传输协议?

UDP如果想成为可靠的传输协议,可仿照TCP协议,对其添加序号保证数据到达的次序,添加确认应答机制保证对端收到数据,添加超时重传机制保证数据都能到达。

本篇文章只是记录自己在学习过程中遇到的一些问题,并不对具体的基础只是进行描述,感兴趣的对着可以参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值