这已经是一个被问烂的面试题了,可能面试官觉得只要你是个人,那你就必须会这个。
我也从网站看了好多讲解这个的博客,大体上来说没有什么差别,唯一的差别也就是有人讲的细致,有人讲的浅显。
我也是为了巩固一下,所以也写一遍博客来聊聊这个。
众所周知,TCP位于OSI七层模型协议中的第四层,属于运输层。运输层的主要任务就是负责为两台主机进程之间的通信提供通用的数据传输服务。
运输层主要使用两种协议:
1、传输控制协议TCP(Transmission Control Protocol) 提供面向连接的,可靠地数据服务。
由于是面向连接的,所以在传送数据之前必须先建立连接,数据传送完后要释放连接,这就增加了很多开销,若确认、流量控制、计时器等。TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。
2、用户数据协议UDP(User Datagram Protocol) 提供无连接的,尽最大努力来传输数据的服务(不保证数据传输的可靠性)
UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 确是一种最有效的工作方式(一般用于即时通信),比如: QQ 语音、 微信视频 、直播等等。
先看看TCP的首部格式,以便更好的理解三次握手和四次挥手。
- 源端口和目的端口:各占2个字节,分别写入源端口和目的端口。
- 序号:占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。例如,一段报文的序号字段值是 301 ,而携带的数据共有100字段,显然下一个报文段(如果还有的话)的数据序号应该从401开始。
- 确认号:占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。例如,B收到了A发送过来的报文,其序列号字段是501,而数据长度是200字节,这表明B正确的收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。
- 数据偏移:指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
- 保留:占6位,保留今后使用,但目前应都位0。
- URG:该位设为 1,表示包中有需要紧急处理的数据,对于需要紧急处理的数据,与后面的紧急指针有关。
- ACK:该位设为 1,确认应答的字段有效,TCP规定除了最初建立连接时的 SYN 包之外该位必须设为 1。
- PSH:该位设为 1,表示需要将收到的数据立刻传给上层应用协议,若设为 0,则先将数据进行缓存。
- RST:该位设为 1,表示 TCP 连接出现异常必须强制断开连接。
- SYN:用于建立连接,该位设为 1,表示希望建立连接,并在其序列号的字段进行序列号初值设定。
- FIN:该位设为 1,表示今后不再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位置为 1 的 TCP 段。
- 窗口:占2个字节,用来通知接收方,发送的报文你需要有多大的空间来接收。
- 检验和:占2个字节,用来校验数据和首部这两个部分。
- 紧急指针:占2个字节,用来指出报文段中紧急数据的字节数。
- 选项:长度可变,用来定义一些其他可选的参数
TCP建立连接(三次握手)
从上图可以看出哪个是客户端哪个是服务器。
这里假设客户端为A,服务器为B
服务器B一直处于LISTEN状态,等待客户端的连接
1、A向B发送连接请求报文,将SYN置为1,并生成一个随机序号seq=x。
2、B收到A发送过来的请求报文,如果同意连接,则向A发送连接确认报文,将SYN置为1,ACK置为1,确认号ack=x+1,为什么要将确认号ack=x+1呢?首先x是刚才第一次A发送请求的时候发送过来的seq,此时将ack=x+1就是告诉A连接服务器成功并且是同一个服务器。然后B在发送一个seq=y
3、A收到B的连接确认报文后,也要向B发送链接确认报文,确认号ack=y+1,序号为x+1,原因同上。
B收到A的确认后,建立连接
为什么要三次
1、第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
2、客户端和服务器通信前要进行三次握手的目的就是确保自己和对方的收、发能力都是正常的。
第一次握手:客户端发送网络包,服务器收到了。这时候服务器就能得出结论:客户端的发送能力是正常的,服务器的接收能力是正常的。
第二次握手:服务器发包,客户端收到了。从客户端的角度看,我收到了服务器发送过来的响应数据包,说明服务器在第一次接收到了我发过去的网络包,并成功发送了响应包。这就说明,服务器的接收、发送能力是正常的。另一方面,我收到了服务器发过来的响应数据包,那么我第一次发送过去的网络包成功到达服务器,这也证明了我自己的接收、发送能力是正常的。
第三次握手:客户端发包,服务器收到了。从而服务器得出结论:客户端的接收、发送能力是正常的,服务器的接收、发送能力是正常的。在第一、二次握手后,服务器只知道客户端的发送能力和服务器的接收能力正常,并不知道客户端的接收能力和服务器的发送能力是否正常。而在第三次握手之后,服务器收到了客户端对第二次握手做出的回应,从服务器的角度看,我第二次发送出去的数据包发送了出去,客户端也收到了。所以我的发送能力是正常的,客户端的接收能力也是正常的。
经过上面的三次握手,客户端和服务器都明确了自己的接收、发送能力是正常的,因此就可以开始正常通信了。
TCP断开连接(四次挥手)
下面就对上图的每个步骤做出解释
1、客户端想断开连接了,就发送一个连接释放报文,其中将首部的FIN置为1就表示要断开连接,在包含一个随机序列seq=x,此时客户端进入FIN_WAIT_1状态。
2、服务器收到客户端发过来的连接释放报文,于是就回应一个确认报文,将首部的ACK置为1,ack=x+1,此时服务器进入CLOSE_WAIT状态。客户端收到服务器的确认请求后,进入FIN_WAIT_2状态,等待服务器发送释放连接报文。
3、此时服务器发送连接释放报文,将首部的FIN置为1,同时携带一个序号seq=y
4、客户端收到连接释放报文后,发出确认,将首部的ACK置为1,ack=y+1,此时客户端就进入了TIME_WAIT状态。
为什么建立连接要三次,而断开连接要四次呢?
1、TCP连接是双向传输的对等的模式,就是说双方都可以同时向对方发送或接收数据。当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。
2、这时对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,也就是说,服务器收到客户端的 FIN 标志,知道客户端想要断开这次连接了,但是,我服务器,我还想发数据呢?我等到发送完了所有的数据后,会发送一个 FIN 段来关闭此方向上的连接。接收方发送 ACK确认关闭连接。
3、客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
4、因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发。
TIME_WAIT
有必要说一下这个,因为面试的时候可能也会捎带上问。
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
1、确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
2、等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
好了关于TCP的三次握手和四次挥手到这就说完了,可能有点乱,但基本上就是这些概念,通读一遍可能记忆不会太深刻,建议大家掌握其原理。
提交评论
您尚未登录 :-( ,登录之后方可评论 登录 or 注册