TCP三次握手和四次挥手详解

在建立TCP的过程中,会用到三次握手和四次挥手,三次握手和四次挥手到底是什么?在哪里用到?

简介

  确切的说在Java的socket编程中,是不用关心三次握手和四次挥手的,这是TCP/IP分层中的传输层需要完成的事情,但是作为原理是有必要了解的
  那么在TCP协议编程的过程中,哪一步用到了三次握手四次挥手?通过一张图来看一下:
在这里插入图片描述
  这是一个利用TCP构建的一个C/S模型,这里只做简略介绍(Java构建C/S),服务器端需要完成绑定端口,监听并返回客户端发来的连接,读写,然后关闭资源。客户端需要连接服务器端,读写,关闭资源。
  从图上可以看到,在客户端发起的connect过程中,服务器端一直等待accpet中,发生了三次握手,也就是只有通过三次握手,这次连接才能建立。
在服务器端和客户端关闭资源的过程中,发生了四次挥手,也就是说,当四次挥手完成后,服务器端和客户端才可以安全的退出。

首先需要了解TCP的文段格式
TCP头部的这张图放在这里以作参考
在这里插入图片描述
源端口和目的端口:各占2个字节,分别写入源端口和目的端口;

序号:占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。例如,一段报文的序号 字段值是 301 ,而携带的数据共有100字段,显然下一个报文段(如果还有的话)的数据序号应该从401开始;

确认号:占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。例如,B收到了A发送过来的报文,其序列号字段是501,而数据长度是200字节,这表明B正确的收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701;

数据偏移:占4位,它指出TCP报文的数据距离TCP报文段的起始处有多远;

保留:占6位,保留今后使用,但目前应都位0;

紧急URG:当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据;

确认ACK:仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1;

推送PSH:当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1;

复位RST:当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接;

同步SYN:在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1;

终止FIN:用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;
窗口,占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受;

检验和:占2字节,校验首部和数据这两部分;

紧急指针:占2字节,指出本报文段中的紧急数据的字节数;

三次握手

  TCP是传递信息首先需要建立连接,就和打电话一样,首先需要互相表明身份后才可以继续通话。

为什么需要三次握手呢?

1.第一种理解:
  客户端给服务器端发送了一个消息,服务器端收到了消息。这个时候服务器端可以知道客户端可以发送消息了,服务器自己可以接收消息了,但是不知道服务器自己是否可以发消息,也不知道客户端是否可以接收消息,客户端是什么都不知道。这是第一次握手
  第一次握手完成后,服务器端向客户端发送了确认消息,客户端收到后。服务器端知道了服务器自己可以接收发送消息,客户端可以发送消息。客户端知道了自己可以接收发送消息,也知道了服务器端可以接收发送消息。这就是第二次握手,但是这个时候服务器端是不知道客户端是否可以接收消息 ,所以需要第三次握手。
  第三次握手客户端再次给服务器端发送确认消息,服务器端综合以前的消息,并且在这次确认中知道了客户端可以接收消息,连接建立完成。

2.第二种理解:
  也可以这样理解,在客户端给服务器端发送完成消息后就下线了,服务器端接收到客户端的消息后,会给客户端发送一条确认消息,如果这个时候连接建立的话,服务端是不知道客户端是否能正确到确认消息。

3.第三种理解:
  就是为了让对方知道数据到底是从哪里开始的,seq是多少就决定了数据是从哪里开始的,知道后给对端进行回应

通过底层原理来了解一下三次握手是如何建立的

在这里插入图片描述

第一次握手

  整个过程是由客户端发起的,也就是connect,将SYN置为1,SYN就是建立时用来同步序号的,seq是客户端随机的一个值,代表传输的序号。发送完毕客户端进入SYN-SENT状态。

第二次握手

  服务器端在接收到数据之前一直处于LISTEN状态,接收到消息后,会给客户端回一条消息进行第二次握手,这时SYN置为1,用于建立连接,ACK=1,这个是确认用的,只有ACK=1时确认序号才会生效,ack也就是确认序号=x+1,就是客户端发给服务器端的序号加1,并生成一个随机的序号y,然后将这条消息发送给客户端,发送完毕进入SYN-RCVD状态。

第三次握手

  客户端接收到服务器端的回复后,会给服务器端回一条确认消息,发出消息后客户端就意味着三次握手已经完成,所以消息中SYN没有置为1,只是确认信息,ACK=1,确认序号ack=y+1。算上第一次客户端给服务器端发消息,这是第二次,第一次seq=x,所以这次是seq=x+1。发送完消息进入ESTAB-LISHED状态。注意seq只是一个序号,只是第一次随机生成的,生成后,以后每次发消息都是加1,最大为65535,达到这个数字后又重新从0开始。
  TCP规定第三次握手是可以携带数据的
  服务器端接收到这个确认信息后,也进入ESTABL-LISHED状态,整个连接就建立了。

四次挥手

四次挥手在socket编程中,就是任意一方调用close的过程
在这里插入图片描述

第一次挥手

  客户端发起第一次挥手,FIN置为1,序号seq是传输数据的最后一个序号值加1,为u,发送完后客户端进入FIN-WAIT-1

第二次挥手

  服务器端接收到客户端的关闭消息后,会通知应用程序关闭,然后会给客户端回一条确认消息,ACK置为1,确认序号ack=u+1,本次消息的序号为seq=v,发送完消息后,进入CLOSE-WAIT状态。客户端接收到服务器端的确认信息后,进入FIN-WAIT-2。
  需要注意的是进入CLOSE-WAIT状态的服务器还是可以给客户端发送消息的,客户端也可以接受到服务端发送的消息

第三次挥手

  服务器端被动关闭,这时会给客户端发送一条关闭确认信息,FIN置为1,ACK=1,确认序号不变,还是u+1,由于可能在半关闭状态下服务器可能给客户端发送了一些消息,所以本次消息序号为w。发送完毕后服务器端进入LAST-ACK,等待确认

第四次挥手

  客户端收到服务器端的关闭消息后,会回一条确认信息,ACK=1,ack=w+1,seq=u+1。在2MSL后客户端关闭,服务器端接收到确认信息后也会关闭。

为什么需要等待2MSL后才关闭

MSL为最长报文段寿命,规定MSL为2分钟,Linux下MSL为30秒

等待的原因:

  1. 为了让对端有足够的时间接受到ACK包,如果对端没有接收到ACK包,那么会导致对端重发FIN,一来一去就是2MSL
  2. 为了避免新旧连接混肴,有些路由器会缓存IP包,如果连接被重用了,这些延迟的包就会和后面的混在一起
为什么需要四次挥手

  因为TCP是全双工的,也就是说在同一时刻不论是客户端还是服务端都可以同时发送消息和接受消息,发送方和接收方都需要FIN和ACK,一个两次,看起来也就是四次了。

服务器端出现大量CLOSE_WAIT状态的原因

  对方关闭socket后,我方忙于读或者写,没有及时关闭连接,主要问题可能是在代码中没有及时的释放资源

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值