TCP/IP协议到底是什么?
作者:卡卷网发布时间:2025-02-25 22:36浏览数量:48次评论数量:0次
候选者:面试官你好,请问面试可以开始了吗
面试官:嗯,开始吧
面试官:今天来聊聊TCP吧,TCP的各个状态还有印象吗?
候选者:还有些许印象的,要不我就来简单说下TCP的三次握手和四次挥手的流程吧
候选者:说完这两个流程,就能把TCP的状态给涵盖上了
面试官:可以吧
候选者:在说TCP的三次握手和四次挥手之前,我先给你画下TCP的头部格式呗(:
候选者:对于TCP三次握手和四次挥手,我们最主要的就是关注TCP头部的序列号、确认号以及几个标记位(SYN/FIN/ACK/RST)
候选者:序列号:在初次建立连接的时候,客户端和服务端都会为「本次的连接」随机初始化一个序列号。(纵观整个TCP流程中,序列号可以用来解决网络包乱序的问题)
候选者:确认号:该字段表示「接收端」告诉「发送端」对上一个数据包已经成功接收(确认号可以⽤来解决网络包丢失的问题)
候选者:而标记位就很好理解啦。SYN为1时,表示希望创建连接。ACK为1时,确认号字段有效。FIN为1时,表示希望断开连接。RST为1时,表示TCP连接出现异常,需要断开。
候选者:下面就先从三次握手开始吧,期间我也会在三次握手中涉及到的TCP状态也说下的。
候选者:TCP三次握手的过程其实就是在:确认通信双方(客户端和服务端)的序列号
候选者:它的过程是这样的
候选者:在最开始的时候,客户端和服务端都处于 CLOSE 状态
候选者:服务器主动监听某个端口,处于 LISTEN 状态
候选者:客户端会随机生成出序列号(这里的序列号一般叫做client_isn),并且把标志位设置为SYN(意味着要连接),然后把该报文发送给服务端
候选者:客户端发送完SYN报文以后,自己便进入了 SYN_SEND 状态
候选者:服务端接收到了客户端的请求之后,自己也初始化对应的序列号(这里的序列号一般叫做 server_isn)
候选者:在「确认号」字段里填上client_isn + 1(相当于告诉客户端,已经收到了发送过来的序列号了) ,并且把 SYN 和 ACK 标记位都点亮(置为1)
候选者:把该报文发送客户端,服务端的状态变成 SYN-REVD 状态
候选者:客户端收到服务端发送的报文后,就知道服务端已经接收到了自己的序列号(通过确认号就可以知道),并且接收到了服务端的序列号(server_isn)
候选者:此时,客户端需要告诉服务端自己已经接收到了他发送过来的序列号,所以在「确认号」字段上填上server_isn+1,,并且标记位 ACK 为1
候选者:客户端在发送报文之后,进入 ESTABLISHED 状态,而服务端接收到客户端的报文之后,也进入 ESTABLISHED 状态
候选者:这就是三次握手的过程以及涉及到的TCP状态
候选者:总结下来,就是双方都把自身的序列号发给对方,看对方能不能接收到。如果「确认可以」,那就可以正常通信。(三次握手这个过程就可以看到双方都有接收和发送的能力)
面试官:那两次握手行吗?
候选者:两次握手只能保证客户端的序列号成功被服务端接收,而服务端是无法确认自己的序列号是否被客户端成功接收。所以是不行的(:
面试官:了解了,那我想问问序列号为什么是随机的?以及序列号是怎么生成的?
候选者:一方面为了安全性(随机ISN能避免非同一网络的攻击),另一方面可以让通信双方能够根据序号将「不属于」本连接的报文段丢弃
候选者:序列号怎么生成的?这…随便猜下就应该跟「时钟」和TCP头部的某些属性做运算生成的吧,类似于雪花算法(:具体我忘了。
面试官:既然网络是不可靠的,那建立连接不是会经过三次握手吗?那要是在中途丢了,怎么办?
候选者:假设第一个包丢了,客户端发送给服务端的 SYN 包丢了(简而要之就是服务端没接收到客户端的SYN包)
候选者:客户端迟迟收不到服务端的ACK包,那会周期性超时重传,直到收到服务端的ACK
候选者:假设第二个包丢了,服务端发送的SYN+ACK包丢了(简而要之就是客户端没接收到服务端的SYN+ACK包)
候选者:服务端迟迟收不到客户端的ACK包,那会周期性超时重传,直到收到客户端的ACK
候选者:假设第三个包丢了(ACK包),客户端发送完第三个包后单方面进入了 ESTABLISHED 状态,而服务端也认为此时连接是正常的,但第三个包没到达服务端
候选者:一、如果此时客户端与服务端都还没数据发送,那服务端会认为自己发送的SYN+ACK的包没发送至客户端,所以会超时重传自己的SYN+ACK包
候选者:二、如果这时候客户端已经要发送数据了,服务端接收到了ACK + Data数据包,那自然就切换到 ESTABLISHED 状态下,并且接收客户端的Data数据包
候选者:三、如果此时服务端要发送数据了,但发送不了,会一直周期性超时重传SYN + ACK,直到接收到客户端的ACK包
面试官:嗯,是不是要讲下四次挥手了?
候选者:嗯,在建立完连接之后,客户端和服务端双方都处于 ESTABLISHED 状态状态
候选者:断开连接双方都有权利的,下面我还是以客户端主动断开为例好啦。
候选者:客户端打算关闭连接,会发 FIN 报文给服务端(其实就是把标志位 FIN 点亮),客户端发送完之后,就进入FIN_WAIT_1状态
候选者:服务端收到 FIN 报文之后,回复 ACK 报文给客户端(表示已经收到了),服务端发送完之后,就进入 CLOSE_WAIT 状态
候选者:客户端接收到服务端的 ACK 报文,就进入了 FIN_WAIT_2 状态
候选者:这时候,服务器可能还有数据要发送给客户端,等服务端确认自己已经没有数据返回给客户端之后,就发送FIN报文给客户端了,自己进入 LAST_ACK 状态
候选者:客户端收到服务端的FIN报文之后,回应ACK报文,自己进入 TIME_WAIT 状态
候选者:服务端收到客户端的ACK报文之后,服务端就进入 CLOSE 状态
候选者:客户端在TIME_WAIT等到2MSL,也进入了 CLOSE 状态
候选者:四次挥手的流程到这里就结束了,结合三次握手,TCP的各个状态也已经说完了。
面试官:嗯嗯,刚聊完四次挥手嘛,那你觉得为什么是四次呢?
候选者:其实很好理解,当客户端第一次发送 FIN 报文之后,只是代表着客户端不再发送数据给服务端,但此时客户端还是有接收数据的能力的。而服务端收到FIN报文的时候,可能还有数据要传输给客户端,所以只能先回复 ACK给客户端
候选者:等到服务端不再有数据发送给客户端时,才发送 FIN 报文给客户端,表示可以关闭了。
候选者:所以,一来一回就四次了。
面试官:从四次挥手的流程上来看,有个 TIME_WAIT 状态,你知道这个状态干什么用的吗?(等待 2MSL)
候选者:主要有两个原因吧。1.保证最后的 ACK 报文 「接收方」一定能收到(如果收不到,对方会 重发 FIN 报文)2. 确保在创建新连接时,先前网络中残余的数据都丢失了
候选者:其实也比较好理解的。就正如我们重启服务器一样,会先优雅关闭各种资源,再留有一段时间,希望在这段时间内,资源是正常关闭的,这样重启服务器(或者发布)就基本认为不会影响到线上运行了。
面试官:假设 TIME_WAIT 状态多过会有什么危害?怎么解决呢?
候选者:从流程上看, TIME_WAIT 状态 只会出现在 主动发起 关闭连接的一方。危害就是会占用内存资源和端口呗(毕竟在等待嘛),解决的话,有Linux参数可以设置,具体忘了额。
面试官:今天最后再问个问题吧,我们常说TCP连接,那这个连接到底是什么?你是怎么理解的?
候选者:其实从三次握手可以发现的是,TCP建立连接无非就是交换了双方的状态(比如序列号)。然后就没有然后了…连接本质上「只是互相维持一个状态,有连接特性」
面试官:好吧。
Java开源项目推荐
我推荐一个校招和社招都好使的开源项目,已经有不少的同学通过这个项目拿到了大厂的offer啦(美团/vivo/阿里/快手/饿了么/腾讯等等)
该项目业务极容易理解,代码结构是比较清晰的,最可怕的是几乎每个方法和每个类都带有中文注释,并且代码完全通过阿里开发插件检查。
拥有非常全的文档,作者从零搭建的过程都有详细地记录,项目里使用了蛮多的可靠和稳定的中间件的。在使用每一个技术栈之前作者都讲述了为什么要使用,以及它的业务背景。我看过,他所说的场景是完全贴合线上环境的。
我感觉这个项目就是奔着真实互联网线上项目去设计和实现的,将项目克隆下来把中间件换成目前公司在用的,配合自身的需求完善下基础建设,它就能在线上运行了。
我跟着README文档的部署使用姿势很快就能跑起来,最少只需要依赖MySQL和Redis。作者还搞了个前端功能界面,这就让系统变得更好理解了。而且,在GitHub或者Gitee所提的Issue几乎都会有回复,看出来也非常乐于合并开发者们的pull request,会让人参与感贼强。
我相信在校、工作一年左右或常年做内网CRUD后台的同学去看看肯定会有所启发,作者也会经常在群里回答该项目相关的问题和代码设计思路。
项目里会应用到各种设计模式(我稍微看了下,应该有7~8种吧),用到了各种的好用的工具组件,动态线程池、日志切面组件之类,都是主流的技术栈...目前这个项目GitHub和Gitee加起来已经 11K+ stars了!
项目Gitee链接:
Java3y/austin项目GitHub链接:
GitHub - ZhongFuCheng3y/austin: 消息推送平台 推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等消息类型。所使用的技术栈包括:SpringBoot、SpringDataJPA、MySQL、Docker、docker-compose、Kafka、Redis、Apollo、prometheus、Grafana、GrayLog、Flink、Xxl-job、Echarts等等github.com/ZhongFuCheng3y/austingithub.com/ZhongFuCheng3y/austingithub.com/ZhongFuCheng3y/austin项目文档&视频:
项目文档&视频项目介绍
核心功能:统一的接口发送各种类型消息,对消息生命周期全链路追踪。
意义:只要公司内部有发送消息的需求,都应该要有类似消息推送平台的项目。消息推送平台对各类消息进行统一发送处理,这有利于对功能的收拢,以及提高业务需求开发的效率。
技术栈
技术栈 | 实现 |
---|---|
编程语言 | Java(JDK 1.8) |
项目管理工具 | Maven 3.x |
集成开发工具 | IDEA 2022 |
部署服务器 | Centos 7.6 |
系统部署工具 | Docker & Docker-compose |
项目环境 | SpringBoot 2.5.6 |
关系型数据库 | MySQL 5.7.X |
缓存数据库 | Redis:lastest |
ORM框架 | SpringData JPA 2.5.6 |
分布式定时任务框架 | XXL-JOB v2.3.0 |
分布式配置中心 | Apollo & Nacos |
消息队列 | Kafka & RabbitMQ & RocketMQ |
分布式日志采集框架 | Graylog |
分布式计算引擎 | Flink 1.16.0 |
监控采集组件 | Prometheus |
监控可视化组件 | Grafana |
数据仓库 | Hive 2.3.2 |
大数据环境 | Hadoop 2.7.4 |
大数据可视化 | Metabase:lastest |
前端技术 | Amis |
使用教程
项目有预览地址,可自行体验:http://119.91.205.248:3001/
1、创建需要发送的渠道账号
2、创建消息模板
3、测试发送消息是否正常
4、查看消息下发情况
5、亦可在新建模板时选择定时任务,通过上传csv文件和指定cron表达式实现下发消息
工程模块&系统流程
了解工程模块的职责,这对看项目代码的时候会有个比较清晰的认识:
工程模块 | 作用 |
---|---|
austin-common | 项目公共包:存储着项目公共常量/枚举/Bean |
austin-support | 项目工具包:对接中间件/组件 |
austin-cron | 定时任务模块:对xxl-job封装和项目定时任务逻辑 |
austin-web | 后台管理模块:提供接口给前端调用 |
austin-service-api | 消息接入层接口定义模块:只有接口和必要的入参依赖 |
austin-service-api-impl | 消息接入层具体实现模块:真实处理请求 |
austin-handler | 消息处理逻辑层:消费MQ下发消息 |
austin-stream | 实时处理模块:利用flink实时处理下发链路数据 |
austin-data-house | 数据仓库模块:消费MQ数据写入hive |
项目Gitee链接:
Java3y/austin项目GitHub链接:
GitHub - ZhongFuCheng3y/austin: 消息推送平台 推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等消息类型。所使用的技术栈包括:SpringBoot、SpringDataJPA、MySQL、Docker、docker-compose、Kafka、Redis、Apollo、prometheus、Grafana、GrayLog、Flink、Xxl-job、Echarts等等github.com/ZhongFuCheng3y/austingithub.com/ZhongFuCheng3y/austingithub.com/ZhongFuCheng3y/austin项目文档:
项目文档&视频
免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。
相关推荐

你 发表评论:
欢迎