linux网络中TCP的三次握手和四次挥手最详细总结
**
因为本人之前一直写的是云笔记,对自己学会的东西作一个总结,所以基本都是文字,本来想全发成博客的形式,发现全发成博客比较花费时间,而且一直发博客质量不是很好,而且通过发博客学到的东西也会变少,所以准备先把笔记发出来,后续再将它们改成博客的形式,争取2天至少改一篇博客,觉得我总结的还行的可以先关注我,后续会发成博客形式,内容也会更加完善
**
TCP:的三次握手:
第一次要发送连接请求时,因为服务器并不知道客户端要发送连接请求,所以客户端需要发送一个SYN请求,和一个seq***,SYN为1时才有效,刚开始这个***是随机的,目的是为了安全,另外TCP要发送数据每次发送的都是tcp的数据包,这个包中有很多信息,里面就包含了ack(这个ack刚开始是没有的,因为没有要确认的***)和SYN,然后seq是这个包的***,tcp为了保证顺序,所以每次发送包就一定会有一个***用来标志这个包,因为刚开始建立连接时,里面信息很少,仅有源端口和目的端口再加上seq和SYN信息,SYN就是建立连接的请求,三次握手就是为了让它成功,这是第一次握手,成功后客户端进入SYN_SEND状态等待服务端响应
当服务端收到客户端发送过来的tcp包时,发现这个客户端想和它建立连接,这时,它也请求和客户端建立连接,发送SYN请求SYN=1,随机生成一个***seq,发送它的tcp包,同时这个tcp包中还有对客户端··请求的确认信息,ACK=1确认同意客户端的SYN请求,同时还要发送一个ack=seq+1(这个***的确认信息,因为刚开始并没有实际发送数据,只是发送空包来建立连接,为了确定包序,所以在进行回复时会给发送方的seq加1,表示接收到了这个TCP包,并且我下次会接收seq加1的这个***的包,来区分上一包和下一个包,所以ack=seq+1(这个seq不是刚才服务端生成的seq,是客户端发过来的seq),它不仅表示确认收到这个tcp包,还间接的协商了下一次所传的序号为多少(在真正进行通信时这个序号为,原本的序号加上所传数据的长度)然后将这个包发送过去,这就是第二次握手,完成后服务端进入SYN_rcvd状态等待客户进行确认
当客户得到服务端发送过来的tcp包后,发现服务端对自己发送过去的SYN请求和seq进行了确认(还协商下一次它要给服务端发送的***为ack),同时服务端也发送了自己的请求信息,所以客户端,发送tcp包,里面对SYN请求进行了确认,发送了一个ACK=1,同时对它的seq也进行了一个确认为ack=seq+1,以之前协商好的ack为seq序号为这次包序号,发送过去,这是第三次握手,完成后客户端进入ESTABLISHED建立连接状态
当服务端收到客户端的确认信息后,也进入ESTABLISHED状态,不对客户端进行回复,并且下因为没有协商下一次,客户端给服务发送的***,所以依然给上次的***
三次握手可能产生的错误:
第一次客户端给服务端发送TCP包时,如果失败,就会超时重传,当发送时,tcp会自动启动一个安全措施,就是在3分钟内不能改变改变SYN+ACK的值,不然可能造成丢包
当服务端收到tcp包后,发送确认信息时,可能一直没有回应,这时会触发超时重传机制,最大的问题是SYN泛洪攻击(这个攻击是指,由一个主机模拟出大量的假ip地址,给服务端发送SYN请求,因为服务端会有半连接队列(专门存储还没有完成连接的SYN),这时因为服务端在接到请求后会,给客户端发送确认信息,但因为这些ip都是假的,所以会陷入超时等待,但由于几乎是同时发起的SYN请求,所以会占满整个半连接队列,这时真正的客户的请求就过不来了)针对这个问题,有一个解决方法就是,当SYN过来时,不先存入队列,先进行一些计算,确认是真ip发过来的请求后,再存入队列
最后一个错误,就是最后一次握手时,客户端成功建立连接后,服务并没有收到确认回复,但客户端已经建立连接,当超过一定重传次数后,服务端会关闭这个连接,不进行重传,目的还是为了防止SYN泛洪攻击,但客户端认为连接已经建立,当发送数据时,服务端会回复rst错误,客户也就断开连接了
进行通信时:
开始通信后,客户用的***依然是之前协商的***,并且通信时,任何一方进行数据发送,另一方必须作出响应,对之前发送的包进行确认,如果自己没有数据要发送(这时等待确认的只有seq,所以确认时只要发送ack(这个ack的值是客户端发送过来的seq值加上发送的数据大小而生成的值)和它自己的seq就行了,之后如果想服务端想对客户端发送数据按只要按原来的序号发送就行了(因为客户端并不对这次的确认信息作出响应 )如果对方没有收到确认信息,就会超时重传,另外在进行数据包传输时,TCP是通过一个滑动窗口机制来进行正常数据的传输的,并不是客户端发送一个数据包,然后服务端发送一个确认包,然后客户端才可以继续发送数据包
TCP的四次挥手:
当客户端发送完数据后,觉得自己没有数据可以发送了,所以它要关闭自己和服务端的通信,
但因为tcp全双工的通信,所以,客户端不确定服务端是否已经将数据给它发送完毕,所以它只能先请求将自己的那一边通信关闭(也就是它不在给服务端发送数据,也发送不了数据,但服务端还能给它发送数据),所以,它在tcp包中加入FIN的关闭请求,当FIN=1时,这个请求才发送成功,然后它以上次通信时所协商的ack作为seq,来发送tcp包给服务端发送。这是第一次挥手,完成之后进入FIN_WAIT1状态
当服务端收到客户端发送的tcp包后,发现客户端想和它断开连接,但是因为它可能自己还在给客户端传送数据,所以还不能关闭自己和客户端的通信,所以这时,为了让客户端得到响应,发送一个tcp包,里面的确认序号ack=seq+1(因为第一次挥手时发送的是一个断开连接的包,相当于一个空包),然后将之前与客户端协商好的序号(ack)做为这次发送的序号为seq,发送tcp包,这是第二次挥手,然后服务端进入close_wait状态(并没有真正和同意客户端的请求,只是说了一声我知道了,你先等着吧),该状态是收到FIN却没有发出ACK的状态(这时服务端能发送tcp包的原因是,它先把之前还没有发送的数据停下来,然后先发送这个包,之后继续传输数据)
当客户端接收到服务端发送过来的tcp包后,进入fin_wait2状态,等待服务进行关确认
当服务端传输数据完成后,对客户端发送tcp包其中的序号还是上次发送的序号seq(因为上次发送信息后并没有协商下次发送的***),并且服务端也请求和客户端断开连接,发送一个FIN=1,并且对客户端发送过来的FIN进行确认,发送ACK=1确认信息,这是第三次挥手,进入LAST_ACK状态
当客户端收到服务端发送的tcp包后,发现服务端对上次的FIN进行了确认,然后还发送了一个服务端的FIN请求,然后客户端发送一个tcp包,里面的信息有,发送一个ACK=1对服务端的FIN进行一个确认,并且发送一个ack = seq+1对服务端的***进行一个确认,然后发送之前协商的ac为这次的seq序号进行tcp包的传输,这是第四次挥手,然后进入TIME_WAIT状态(这个状态需要等待两个msl时间,原因是它进行确认后,如果服务端没有收到它的回复,而它已经关闭了,那么就会触发tcp的超时重传机制,但这时客户端已经关闭,肯定是传不过来的,这时服务端就会向高层报告错误,这样不符合tcp的传输机制,并且还有一种可能,就是当客户端关闭连接后,又发起了一个新连接,但由于前面的传输还可能有残余,服务端可能把它当成了新连接的请求去连接,这样可能会和真正的连接混淆,产生错误,所以针对第一个错误,等待2个msl时间的原因是客户端发送最大生存时间是1msl,服务端如果没有收到重发最大时间又是1msl,所以等待2个msl时间,确保服务端收到了,然后就可以正常关闭了,针对第二个错误,等待2个msl
的原因是,传输完成后可能还有残余,让这些残余数据都从网络消失,等待2个可以满足这个需求,同时也可以满足第一个错误的需求)
当服务端收到客户端发送的tcp包后,发现客户端已经确认了它的请求,于是它就可以主动关闭连接了,当过了2个msl时间后,客户端也主动关闭连接。
四次挥手时的错误:
可能任意一方没有收到tcp包,那么就超时重传就行了,还有就是在最后一次挥手时要等待两个msl时间,来处理可能残余的数据