网络原理(二)三次握手、四次挥手

📅 发布时间:2026/10/10 6:08:33
网络原理(二)三次握手、四次挥手
前言hello hello这里是洋不写bug~欢迎大家点赞关注收藏TCP是有连接的这个连接是抽象的通信双方各自保存对方的关键信息IP端口建立连接时需要通过三次握手连接断开时需要通过四次挥手这两个环节是整个网络部分面试最高频、最重要的问题这篇博客就会详细的解析三次握手和四次挥手相关知识个人主页洋不写bug的博客所属专栏JavaEE学习铁汁们对于JavaEE的各种常用核心语法都可以在上面的前端专栏学习专栏正在持续更新中有问题可以写在评论区或者私信我哦~1三次握手1流程TCP通信在建立连接时需要通过三次握手handshake这三次握手传输的是“打招呼”数据包这个数据包中不携带任何的业务数据也就是TCP数据包没有载荷只有报头这个就类似于出去谈业务发现客户对方是多年未见的老同学约在一起吃饭时就先不谈业务先聊一些之前上学的事情以及近况拉近一下感情建立一下连接三次挥手如下图步骤如下客户端给服务器发送个同步报文段syn告诉服务器我要和你建立连接请你保存我的信息synchronized英文翻译是同步这个术语在不同对方有不同含义在多线程中表示的是一种互斥锁在网络编程中表示的就是同步报文段服务器收到后给客户端返回一个应答报文段(ack)告诉客户端收到我会保存信息服务器也给客户端发送个syn告诉客户端我也要跟你建立连接请你保存我的信息客户端收到后给服务器返回一个ack告诉服务器收到我会保存信息因为建立连接是一个相互的过程通过这种方式能保证客户端保存了服务器连接服务器也表示了客户端连接这个过程在逻辑上是四次交互但是中间两次可以合成一个TCP数据包如下图网络上实际只传输了三个数据包因此就称为三次握手区分报文段的类型是看标志位如下图ACK的值为1就说明当前报文段是应答报文段SYN的值为1就说明当前报文段是同步报文段前面提到“三次握手”逻辑上是四次交互有的铁汁可能回想一定要交互四次才能确保建立连接了吗?举个例子博主和哥们在玩pubg开始玩之前前需要验证自己的麦克风和耳机没问题也需要验证对方麦克风和耳机是没问题的如下图首先博主说“能听到我说话吗“哥们听到后就能推断出他自己的耳机没问题也能推断出博主的麦克风没问题博主听到哥们回复的“可以听到”说明哥们收到了前面博主回复的消息说明博主的麦克风和哥们的耳机都没有问题这里博主又听到了哥们的声音说明博主的耳机和哥们的麦克风都没问题这里测试麦克风就相当于测试发送能力测试耳机就相当于测试接收能力如果像上面只进行两次交互的话虽然博主可以推出我们两个的麦克风和耳机都没问题但是哥们是没法确定自己的麦克风和博主的耳机没问题也就是接收方无法确定自己的发送能力和发送方的接收能力没问题所以还要再加上两次交互逻辑哥们问博主说那你能听见我说话吗博主回复说可以哥们就能确定他自己的麦克风和博主的耳机没问题了第二次交互和第三次交互可以合在一起就构成了“三次握手”如下图2作用三次握手主要有两个作用验证通信链路是否畅通验证通信双方的发送能力和接收能力是否正常通过三次握手让通信双方协商关键信息验证通信链路是否畅通就类似于地铁在早上会先空车从头到尾跑一遍线路中间不停不载客因为经过一晚上可能会出现一些异常比如轨道漏水/电路问题先空车跑一遍验证下通行是否正常如果不检测带着一车乘客中途遇到故障停下来就比较麻烦了光是通信链路畅通还不够还需要验证通信双方的发送能力和接收能力是正常的也就是第二点三次握手时通信双方也会协商一些通信过程中的关键信息主要协商的就是TCP数据的起始序号这个序号就是按照字节进行编号方便接收方验证和拼接数据保证数据传输的可靠性网络编程四中有解析如下图每次建立连接时协商出来的编号都是不同的而且编号的差值还是很大的有的铁汁可能会想每次建立连接这个起始序号直接从0/1开始不就行了为什么三次握手时双方要重新协商而且每次建立连接时起始序号的差别值都很大呢这个主要是为了解决网络通信中的一种特殊情况下出现的问题客户端和服务器先通过三次挥手建立了连接接着传输了一段时间数据服务器和客户端断开连接通过四次挥手但是这个断开连接不一定是不通信了可能是客户端想重启一下断开后再去建立连接如下图这时候就会出现一个问题假如有个数据包的传输路径有点拥堵到达服务器的时候这时候已经是其他的连接了如果服务器接收这个数据包的话就会收到一堆莫名其妙、不属于当前会话的脏数据业务直接错乱因此服务器遇到这种上次连接传过来的数据包时就要直接丢弃判断数据包是这次连接传过来的还是上次连接传过来的就是看这个数据包的序号是否跟本次连接的起始序号相接近因此不同连接约定的起始序号的差值要很大三次握手的整套逻辑是在操作系统的内核中完成的客户端在new Socket时就已经触发三次握手了服务器通过accept把已经建立好的连接拿到应用程序中时三次握手就已经完成了TCP通信过程中服务器和客户端涉及到的状态还是比较多的这里先介绍握手时的两种主要状态LISTEN服务器存在的状态服务器new ServeSocket时就会进入LISTEN表示在“监听”这个端口有客户端连接上这个端口就能够accept了ESTABLISHED表示客户端和服务器的连接已经建立好了服务器和客户端就可以进行通信了在命令行上输入netstat -ano就能看到这些连接的状态如下图2四次挥手四次挥手是断开连接时的流程可能时客户端先发起的断开连接也可能是服务器先发起的断开连接而三次握手则一定是客户端先发起的四次挥手流程如下拿客户端发起的举例客户端告诉服务器我要和你断开连接请你把我删了服务器回复收到服务器告诉客户端我也要和你断开连接请你也把我删除了客户端回复收到客户端和服务器把对方的信息之前保存的对方的IP和接口删除掉删除后连接就断开了这个请求断开的报文的标志位中的FIN就是1用来进行标注有的铁汁可能会想既然逻辑上都是四次交互为什么三次握手能把中间两次交互合并成一次发送四次挥手就不行呢三次握手的操作在内核中进行客户端在new Socket时就已经触发三次握手了服务器通过accept把已经建立好的连接拿到应用程序中时三次握手就已经完成了是一定能把中间两次发送合并成一个数据包的四次挥手就不一定能把中间两次发送合并成一个数据包了这个铁汁们可以结合前面的网络编程三中的TCP客户端和服务器的代码来理解当客户端进程退出或者手动调用socket.close()都会触发向服务器发送FIN服务器收到FIN后向客户端发送ACK服务器的processConnection方法如下服务器先用scanner.hasNext()感知到客户端断开连接了退出while(true)循环接着执行socket.close断开跟这个客户端的连接这时候才发送FIN如果代码中在socket.close()前加上一些耗时逻辑那服务器向客户端发送FIN需要等一段时间而服务器回复ACK是在收到客户端的FIN后就立刻回复的这两次逻辑发送是有时间差距的因此没办法合并成一个数据包发送privatevoidprocessConnection(Socketsocket){System.out.printf([%s:%d] 客户端上线\n,socket.getInetAddress().toString(),socket.getPort());try(InputStreaminputStreamsocket.getInputStream();OutputStreamoutputStreamsocket.getOutputStream()){ScannerscannernewScanner(inputStream);PrintWriterwriternewPrintWriter(outputStream,true);while(true){//1.读取请求并解析if(!scanner.hasNext()){System.out.printf([%s:%d] 客户端下线,socket.getInetAddress().toString(),socket.getPort());break;}Stringrequestscanner.next();//2.根据请求计算响应Stringresponseprocess(request);//3.把响应写回客户端writer.println(response);System.out.printf([%s:%d] req%s; resp: %s\n,socket.getInetAddress().toString(),socket.getPort(),request,response);}}catch(IOExceptione){e.printStackTrace();}finally{try{//耗时逻辑socket.close();}catch(IOExceptione){e.printStackTrace();}}}因为不一定每次都能触发合并把两次发送逻辑合并成一个数据包因此就叫做“四次挥手”“四次挥手”过程中有两个状态比较重要TIME_WAITED和CLOSE_WAITCLOSE_WAIT被动断开连接的一方收到FIN后返回ACK同时进入该状态这个状态等待应用程序代码调用close也就是等待关闭这个状态的保持时间并不会太长所以在cmd中用netstat -ano查看连接状态时会发现处于这个状态的连接是很少的TIME_WAIT类似于线程的TIME_WAITED为有限制时间的等待主动发起断开连接的一方在收到对方发回的FIN后返回ACK并且进入TIME_WAIT状态那为什么返回完ACK后不直接close断开连接呢还要先进入TIME_WAIT状态等一会因为发送个ACK可能会出现丢包情况如下图如果客户端没有等直接释放连接了后面服务器触发数据重传重新传输FIN不管触发几次数据重传都不可能收到客户端ACK的回应那这个四次握手过程就没有完成因此客户端需要先等一段时间再断开连接这个TIME_WAIT等待时间就用2 * MSLMaximum Segment Lifetime报文段最大生存时间来计算MSL就可以理解为网络上任意两点之间传输消耗的最大时间但现实中想要准确的测出MSL的值是不现实的就会把MSL的值设置的宽裕一些例如Linux上默认设置的是60s这个时间是远远大于很多节点之间的传输时间的多等一会就是为了避免出现前面提到的ACK丢包后重传FIN无人应答问题结语TCP协议的的关键状态共有四个简单总结如下LISTEN手机开机信号良好可以随时打电话ESTABLISHED连接已经建立电话接听可以说话了CLOSE_WAIT等待代码调用closeTIME_WAIT等待FIN重传应对最后一个ACK丢包的情况三次握手和四次挥手的过程很简单重点是想清楚为什么一定要交互三次/四次在交互时解决了什么样的问题在面试时面试官问到相关知识时可以在纸上简单的画个图结合图来回答问题就会更加清楚以上就是今天的所有内容啦完结撒花