候选人:面试官你好,可以开始面试了吗?面试官:嗯,开始吧面试官:今天聊聊TCP,你对TCP的各种状态还有印象吗?考生:还是有点印象的,还是简单说一下TCP的三次握手和四次挥手的过程考生:说完这两个过程,TCP的状态可以被面试官覆盖考生:之前说到TCP的三次握手和四次握手,我给大家画一下TCP的头部格式(:考生:对于TCP的三次握手和四次握手,我们最重要的是关注序列号,确认号和TCP头的几个标记位(SYN/FIN/ACK/RST)候选:序列号:第一次建立连接时,客户端和服务器都会随机初始化一个序列号。(看在整个TCP过程中,序列号可以用来解决网络包乱序的问题)Candidate:Confirmationnumber:该字段表示“接收端”告诉“发送端”上一个数据包hasbeenreceived成功接收(可以用确认号解决网络丢包问题)考生:标志位很好理解。当SYN为1时,表示要创建连接。当ACK为1时,确认号字段有效。FIN为1时,RST为1时,表示TCP连接异常,需要断开。考生:先从三次握手说起,下面我也说下三次握手涉及到的TCP状态。候选:TCP三次握手的过程其实是:确认双方(client和server)的序号候选:它的过程是这样一个candidate:一开始,client和server都处于CLOSE状态candidate:服务器主动监听某个端口,处于LISTEN状态。Candidate:client会随机生成一个序号(这里的序号一般叫client_isn),并设置flag为SYN(意思是连接),然后向servercandidate发送报文:client发送SYN报文后,进入SYN_SEND状态候选者:服务器收到客户端的请求后,也初始化对应的序号(这里的序号一般称为server_isn)候选者:在“确认号”字段填写client_isn+1(相当于告诉client发送的序列号已经收到),并点亮SYN和ACK标志位(置1)Candidate:向client发送报文,服务端状态变为SYN-REVDCandidate:经过client收到server发过来的消息,就知道server收到了自己的序列号(可以通过确认号知道),收到了server的序列号(server_isn)候选:这时,client需要告诉服务器已经收到他发送的序列号,所以在server_isn+1上填写“确认号”字段,标志位ACK为1处理及涉及的TCP状态候选:总结一下,双方将他们的序列号发送给对方,看看他们是否可以收到。如果“ConfirmedOK”,则可以正常通信。(三次握手过程说明双方都有接收和发送能力)面试官:两次握手还好吗?考生:两次握手只能保证客户端的序列号被服务器成功接收,而服务器无法确认自己的序列号是否被客户端成功接收。所以不行(:面试官:明白了,那我想问一下为什么序列号是随机的?序列号是怎么生成的?应聘者:一方面是为了安全(随机ISN可以避免来自非-identicalnetworks),另一方面,它允许通信双方根据序号丢弃“不属于”连接的报文段。这些属性是通过计算产生的,类似于雪花算法(:我忘记了具体情况。面试官:既然网络不可靠,那不会是三次握手建立连接吧?如果中途迷路了怎么办?候选:假设第一个包丢失,客户端发送给服务器的SYN包丢失(简而言之,服务器没有收到客户端的SYN包)候选:客户端没有收到服务器的ACK对于长时间的包,会周期性超时重传,直到收到服务器的ACK候选:假设第二个包丢失,服务器发送的SYN+ACK包丢失(简而言之,客户端没有没有收到服务器的SYN+ACK包)候选:如果服务器长时间没有收到客户端的ACK包,会周期性超时重传,直到收到客户端的ACK。候选:假设第三个包丢失(ACK包),client发送第三个包后,终端单方面进入ESTABLISHED状态,此时server也认为连接正常,但是第三个包没有reachtheservercandidate:1.如果此时client和server都没有发送数据,server会认为自己发送的SYN+ACK包还没有发送给client,所以会超时重传自己的SYN+ACK包Candidates:2.如果此时client已经发送了数据,server收到ACK+Data包,自然会切换到ESTABLISHED状态,接收来自的Datapacketcandidatesclient:3.如果此时server想发送数据,但是发不出去,会一直周期性的在超时后重传SYN+ACK,直到收到client的ACK包。采访者:那么,你要挥手四次吗?考生:嗯,连接建立后,客户端和服务端都处于ESTABLISHED状态。候选人:双方都有断开连接的权利。我以客户端主动断开连接为例。候选:客户端打算关闭连接,会向服务器发送一个FIN报文(实际上是标志位FIN被点亮),客户端发送报文后进入FIN_WAIT_1状态。候选:服务器收到FIN报文后,回复一个ACK报文给客户端(表示收到),服务器发送后,进入CLOSE_WAIT状态候选:客户端收到ACK后,进入FIN_WAIT_2状态来自服务器的消息。还有数据要发送给客户端。服务器确认没有数据返回给客户端后,向客户端发送FIN报文,进入LAST_ACK状态。候选:客户端收到服务器的FIN报文后,响应ACK报文,进入TIME_WAIT状态候选:服务器收到客户端的ACK报文后,服务器进入CLOSE状态候选:客户端等待2MSL在TIME_WAIT并且也进入CLOSE状态Candidate:四次挥手的过程到此结束。结合三次握手,TCP的各种状态也都说完了。采访者:嗯,刚刚聊天就挥了四次,那你觉得为什么是四次呢?考生:其实很好理解,当客户端第一次发送FIN报文时,只是意味着客户端不再向服务端发送数据,但是此时客户端仍然有接收数据的能力.服务器收到FIN报文时,可能还有数据要发送给客户端,所以只能回复ACK给客户端候选:等到服务器不再有数据要发送给客户端,再发送FIN报文。向客户端发送消息,表示可以关闭。考生:那么,一轮四次。面试官:从四次挥手的过程来看,有一个TIME_WAIT状态。你知道这个状态是干什么用的吗?(等待2MSL)考生:主要有两个原因。1.保证上一个ACK报文的“接收者”能收到(如果没有收到,对方会重新发送FIN报文)2.保证在建立新连接时,之前网络中剩余的数据丢失:其实还是比较容易理解的。就像我们重启服务器一样,我们会先优雅的关闭各种资源,然后再放一段时间。我们希望在这段时间内资源正常关闭,这样重启服务器(或发布)基本不会影响在线资源。有用。采访者:假设不止有TIME_WAIT状态有什么坏处?如何解决?候选:从流程上看,TIME_WAIT状态只会出现在发起关闭连接的一方。坏处就是会占用内存资源和端口(毕竟是等待)。如果解决了,还有linux的参数可以设置,但是忘记多少了。面试官:今天结束的时候再问一个问题。我们经常说到TCP连接,那么这个连接到底是什么呢?你怎么理解的?考生:其实从三次握手可以发现,与TCP建立连接无非就是交换双方的状态(比如序号)。那么就没有了……连接本质上就是“只是相互之间保持一种状态,并且具有连接特性”。面试官:好的。关注我的微信公众号【Java3y】聊点不一样的!【在线面试官+从头写一个Java项目】持续高强度更新!求一星!!原创不易!!一连求三!!
