TCP的三次握手与四次挥手详解

article/2025/9/23 0:42:30

文章目录

    • TCP 协议简述
    • TCP包首部
    • TCP 三次握手建立连接
    • TCP 四次挥手关闭连接
    • 常见面试题:

TCP 协议简述

TCP 提供面向有连接的通信传输,面向有连接是指在传送数据之前必须先建立连接,数据传送完成后要释放连接。TCP传输的是字节流

无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。
同时由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。

TCP包首部

首部的结构由协议的具体规范详细定义。在数据包的首部,明确标明了协议应该如何读取数据。

TCP数据被封装在一个IP数据报中如下图:
在这里插入图片描述
TCP首部如果不计任选字段,它通常是20个字节。最多可以是40字节
在这里插入图片描述
(从这个图上看:一层32位,也就是4个字节,一共5层,共20个字节)

现在分析一下TCP协议首部的各项信息:

  • TCP端口号

TCP的连接是需要四个要素确定唯一一个连接:(源IP,源端口号)+ (目地IP,目的端口号)
所以TCP首部预留了两个16位作为端口号的存储,而IP地址由上一层IP协议负责传递
源端口号和目地端口各占16位两个字节,也就是端口的范围是2^16=65535,另外1024以下是系统保留的,从1024-65535是用户使用的端口范围

  • TCP的序号和确认号:

32位序号 seq:Sequence number 缩写seq ,TCP通信过程中某一个传输方向上的字节流的每个字节的序号,通过这个来确认发送的数据有序,比如现在序列号为1000,发送了1000个字节,下一个序列号就是2000。

32位确认号 ack(小写):Acknowledge number 缩写ack,TCP对上一次seq序号做出的确认号,用来响应TCP报文段,给收到的TCP报文段的序号seq加1

  • TCP的标志位

每个标志位占一位,因此不是0就是1,1为有效,0为无效
每个TCP段都有一个目的,借助于TCP标志位选项就可以确定每个TCP端的发送目的。
用的最广泛的标志是 SYN,ACK 和 FIN,用于建立连接,确认成功的段传输,最后终止连接。

SYN:同步标志位,用于建立会话连接,同步序列号;
ACK: 确认标志位,对已接收的数据包进行确认;
FIN: 完成标志位,表示我已经没有数据要发送了,即将关闭连接;

PSH:简写为P,推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队;
RST:简写为R,重置标志位,用于连接复位、拒绝错误和非法的数据包;
URG:简写为U,紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理;

TCP 三次握手建立连接

所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。

三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手

三次握手过程的示意图如下
在这里插入图片描述

第一次握手:
客户端将TCP报文标志位SYN置为1,随机产生一个序号值seq=J,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待服务器端确认。

第二次握手:
服务器端收到数据包后由标志位SYN=1表示知道客户端请求建立连接,同时将标志位SYN和ACK都置为1,确认号ack=J+1,随机产生一个序号值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。

第三次握手:
客户端收到确认后,检查确认号ack是否为J+1,标志位ACK是否为1,如果正确则将标志位ACK置为1,确认号ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了

注意:我们上面写的ack和ACK,不是同一个概念:

  • 小写的ack代表的是头部的确认号Acknowledge number, 缩写ack,是对上一个包的序号进行确认的号,ack=seq+1。
  • 大写的ACK,则是我们上面说的TCP首部的标志位,用于标志的TCP包是否对上一个包进行了确认操作,如果确认了,则把ACK标志位设置成1。

TCP 四次挥手关闭连接

四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。

由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

四次挥手过程的示意图如下:

在这里插入图片描述
第一次挥手:
Client端发起挥手请求,并且停止发送数据,向Server端发送标志位是FIN报文段,FIN=1,设置序列号seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,Client端进入FIN_WAIT_1(终止等待1)状态,这表示Client端没有数据要发送给Server端了(TCP规定,FIN报文段即使不携带数据,也要消耗一个序号)

第二次挥手:
Server端收到了Client端发送的FIN报文段,向Client端返回一个标志位是ACK=1的报文段,ack设为seq加1(u+1),并且带上自己的序列号seq=v,服务端就进入了CLOSE-WAIT(关闭等待)状态,TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第三次挥手:
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

第四次挥手:
客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端依然没有收到回复,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。可以看到,服务器结束TCP连接的时间要比客户端早一些。

常见面试题:

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。所以建立连接只需要三次握手。
但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

【问题3】为什么需要三次握手?为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

如果使用两次握手就建立连接,就会出现出现以下情况:

  1. 我们假设client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
    假设采用“两次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
  2. 把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下(第二次握手丢失),将不知道S是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。


http://chatgpt.dhexx.cn/article/OGmJaaEL.shtml

相关文章

什么是“三次挥手”和“四次握手”

文章目录 一、为什么要进行三次握手二、握手为什么要三次三、挥手为什么需要三次四、挥手为什么三次不行总结 前言 首先,我们先说什么是”三次握手“和”四次挥手“ 1.我们先来简单介绍一下”三次握手“ (1).先来介绍一下里面这些看起来比较…

简述TCP四次挥手

四次挥手主要用到了两个标志位(ACK&FIN): ACK 示意参考:TCP三次握手FIN: 终止数据传输标志位---->当FIN为1的时候代表此数据为终止断开连接的请求 四次挥手流程: 由于TCP连接是双向传输的对等的模式即双工 wiki百科定义: 全双工(full-duplex)的…

简述四次挥手

什么是四次挥手 由于TCP连接是全双工的,断开一个TCP连接,需要客户端与服务器发送四个包来确认连接的断开 简述四次挥手的过程: 因为TCP是全双工的,因此,每个方向都要单独关闭 当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着 一方向不会再…

三次握手四次挥手

三次握手四次挥手是tcp协议中的,在说三次握手四次挥手先说一下tcp协议和udp协议。 (1)我们常用的网络通信如浏览网页、软件聊天、看的爱奇艺上的视频都是通过tcp、udp这两种协议来进行数据传输的; (2)tcp…

TCP三次握手与四次挥手(详解)

TCP三次握手 一:引出 客户端与服务器之间数据的发送和返回的过程当中需要创建一个叫TCP connection的东西;由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是经过由TCP创建的一个从客户端…

TCP连接的四次挥手全过程

TCP通过四次挥手来释放连接 四次挥手的过程如下: 第一次挥手: 客户端向服务器发送一个 FIN 数据包(FIN 1,seq u)主动断开连接,报文中会指定一个序列号。告诉服务器:我要跟你断开连接了&am…

http三次握手四次挥手详解

1、 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。 四次挥…

TCP四次挥手及原因

聚散终有时,TCP 断开连接是通过四次挥手方式。 双方都可以主动断开连接,断开连接后主机中的「资源」将被释放。 上图是客户端主动关闭连接 : 一次挥手 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文&…

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

文章目录 三次握手和四次挥手简述三次握手的目的三次握手流程详解半连接队列和全连接队列四次挥手的目的四次挥手详解为什么客户端需要TIME_WAIT状态为什么挥手比握手多一次为什么三次挥手不行TCP报文参数释义 三次握手和四次挥手简述 三次握手,即客户端与服务端进…

三次握手,四次挥手,为什么是三次握手四次挥手

三次握手 两次握手(情况1) 两次握手(情况2) OK,下面正经地来回答下这个问题,要搞清楚这个问题,首先得了解TCP究竟是如何保证可靠传输的。 PS:TCP协议中,主动发起请求的一…

TCP三次握手四次断开

转载地址:www.51niux.com IP协议是网络层的主要协议,为上层传输层提供无连接、无状态、不可靠的服务。优点是简单高效。无状态是指各个IP报文是独立传送的,不同步传输状态的信息,所以容易发生重复和乱序的情况。不可靠是指IP协议…

有关三次握手,四次挥手的超详细总结!!!

有关三次握手,四次挥手的超详细总结!!! 我们先来看一下三次握手和四次挥手的示意图: 图示为三次握手。 图示为四次挥手。 一、三次握手和四次挥手的过程: 三次握手: TCP建立连接的过程我们…

TCP四次挥手详解

在开始之前可以先了解一下 TCP三次握手 TCP四次挥手过程和状态变迁 为什么挥手需要四次? 为什么TIME_WAIT等待的时间是2MSL? 等待2MSL的意义 TIME_WAIT状态过多有什么危害? 如何解决TIME_WAIT状态过多? TCP四次挥手过程和…

C++ map遍历

C map遍历 #include <iostream> #include <map>using namespace std;int main() {map<int, int> _map;_map[0] 1;_map[1] 2;_map[10] 10;map<int, int>::iterator iter;iter _map.begin();while(iter ! _map.end()) {cout << iter->firs…

C++ map遍历(简单易记忆)

C中map遍历有两种方法&#xff1a; 第一种&#xff0c;使用迭代器&#xff0c;while循环 #include <iostream> #include <map> using namespace std; int main() {map<int,int> p;p[0] 1;p[1] 2;p[3] 4;map<int,int>::iterator it p.begin();whi…

Java中Map的4种遍历方式

原标题&#xff1a;Java中Map的4种遍历方式 第一种方式&#xff1a;这是平常用的最多也最可取的一种遍历方式。 for (Map.Entry entry : map.entrySet()) { System.out.println(“key” entry.getKey() “,value” entry.getValue()); 第二种方式&#xff1a;如果只需要…

HashMap的几种遍历方式及循环删除

目录 1. 前言2. HashMap 的遍历方式2.1. 迭代器 EntrySet2.2. 迭代器 KeySet2.3. ForEach EntrySet2.4. ForEach KeySet2.5. Lambda 表达式2.6. Streams API 3. 循环删除3.1. 迭代器 Iterator 方式3.2. ForEach 循环方式3.3. Lambda 表达式3.3.1. Lambda 删除的正确方式 3.4. S…

Map遍历四种方式及其效率

目录 1、Map介绍 2、Map数据结构及扩容 2.1、数组&#xff1a;寻址容易&#xff0c;插入和删除元素困难 2.2、链表&#xff1a;寻址困难&#xff0c;插入和删除元素容易 2.3、Map数组长度默认16&#xff0c;扩容负载因子为0.75 3、Map遍历4种方式及其效率 3.1、方式一&a…

前端map循环遍历使用

map定义 Array.map() ⽅法返回⼀个新数组&#xff0c;数组中的元素为原始数组元素调⽤函数处理后的值&#xff0c;同时不会改变原来的数组 var newArra[1,3,6,10,44]; var newArraysnewArra.map((index) > { return index*index }) console.log(newArra); //[1,3,6,10,44]…

map forEach for in 循环遍历

1.map遍历数组对象 var map [{ key : "百度", value : "李彦宏" },{key : "阿里巴巴", value : "马云" },]; for (var key in map) { console.log(map[key]); } 2.forEach遍历数组 forEach()方法需要一个函数作为参数&…