TCP三握手四挥手图解+文件说明+抓包查看

https://img-blog.csdn.net/20180127134632320?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3QxMDI1ODE0NDQ3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

(函数涉及的细节本文不做讨论)

建立连接前服务器和客户端所做准备:

服务器端:服务器通过socket()函数创建socket文件描述符,然后使用bind()函数给该文件描述符绑定一个端口和ip,接着服务器调用listen()函数监听该文件描述符(此文件描述符记录了服务器的IP和端口以及地址类型等),等待客户连接。

客户端:客户端通过socket()函数创建socket文件描述符,可以显示调用bind()函数给该文件描述符绑定一个IP和端口,不过客户端通常不这么做,而是通过调用connect()函数,由内核根据所用外出网络接口来选择客户端的IP地址并选择一个临时可用端口。正是connect()函数触发了TCP三握手,下面详解讲解三握手的过程。

TCP三握手:(按照上图讲解)

第一次握手客户端发送SYN=1 ,seq = 100SYN=1表示请求连接,seq=100表示本报文的序列号是100(因为是第一次握手,所以这也是起始序列号)

第二次握手:服务器收到客户端信息后回送SYN=1ACK=1ack=101seq=500SYN=1表示同意连接,ACK=1表示确认号(ack)有效,seq=500表示本次报文序列号为500ack=101表示100以前的报文(包括100)我都已经收到了,期望你下次报文从101开始发送。

第三次握手:客户端收到服务器消息后便回送:ACK =1 ack=501,seq=101ACK=1表示确认号(ack)有效,ack=501表示500之前的报文(包括500)我都已经收到,期望你下次报文从501开始发送。 

至此TCP三握手完成,连接建立!

 

TCP四挥手:

第一次挥手:客户端发送FIN=1ACK=1seq=122ack=512FIN=1表示请求断开连接,ACK=1表示确认号(ack)有效,seq=122表示本次序列号为122ack=512表示511之前的报文(包括511)我都已经收到,期望你下次报文从512开始发送(本次确认只是重复上一次的确认)

 

第二次挥手:服务器收到客户端的FIN后回送ACK=1ack=123seq=512ACK=1表示确认号(ack)有效。ack=123表示122之前的报文(包括122)我都已经收到,期望你下次报文从123开始发送,seq=512表示本次序列号为512

至此,客户端不会再发送任何数据,但是服务器还可以发送数据,此时的TCP连接处于半关闭。

第三次挥手:服务器没有数据发送时便回送客户端FIN=1ACK = 1,ack=123seq=513FIN=1表示同意断开连接,ACK=1表示确认号(ack)有效,seq=513表示本次序列号为513ack=123表示122之前的报文(包括122)我都已经收到,期望你下次报文从123开始发送 

第四次挥手:客户端收到服务器报文后回送,ACK=1,ack=514seq=123,解释与之前一样。 

至此,TCP连接释放!

让我们通过tcpdump抓包工具查看一下实际过程:、

https://img-blog.csdn.net/20180127171339693?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3QxMDI1ODE0NDQ3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

 Flags标记中 'S' 表示 'SYN' ,'P' 表示 'PUSH', '.'表示'ACK',length代表数据长度,注意:是数据长度,不是整个报文的长度。win是窗口大小。从上图可以看出,实际过程与我们上述讲解的过程完全一致,对于TCP滑动窗口读者自己去查相关知识。

另外我们看到在连接建立的时候双发还发送了MSS值,MSS是Maximum Segment Size ,中文意思:最大报文段长度,他指的是TCP报文段中数据字段的最大长度,MSS值和滑动窗口的win值没有关系。

几个非常重要的问题:

1.为什么必须要三次握手才能确定一条连接,两次不行吗?

回答:假设采取两次握手,客户端请求连接,服务器同意请求,然后连接就建立,会出现什么问题?我们假设客户端发送SYN请求连接,服务器也确实收到了,然后服务器回送SYN同意建议连接,如果服务器回送的SYN的报文在网络中迷失了会怎样,服务器以为客户端收到了自己回送的SYN,所以服务器认为此次连接已经建立了,但是客户端并没有收到服务器回送的SYN,所以客户端以为服务器拒绝了此次请求,认为自己与服务器并没有建立连接。假设过了一段时间后服务器回送的SYN报文在网络中滞留了一段时间后又到达了客户端,但此时客户端认为自己并没有给服务器发送SYN,所以客户端并不会理睬此条报文。只有服务器还仍然维护着这条连接,这样的TCP还可靠吗?


 

2.断开连接一定是发送四次报文吗?

回答:其实并不一定需要四次。

 (1)四次挥手的情况:就拿上文所述断连方式来说是需要四次,当客户端发送FIN后(第一次挥手),服务器回送了确认报文,(第二次挥手)但是此时服务器还有数据要发送,所以服务器将未发送完的数据发送给客户端,然后服务器给客户端发送SYN报文(第三次挥手),表示我没有数据发送了,请求断开连接,接着客户端回送确认报文(第四次挥手),此时连接断开!

(2)三次挥手的情况:客户端发送FIN给服务器(第一次挥手),服务器此时没有数据要发送给客户端,所以服务器发送一条带FIN的确认报文(第二次挥手),也就是将四次挥手的第二次和第三次挥手的报文合并为一条一同发送,客户端收到后服务器报文后回送确认

报文(第三次挥手),此时连接断开!

 下面来看一下tcpdump抓到三次挥手的情况:

https://img-blog.csdn.net/20180127173021029?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3QxMDI1ODE0NDQ3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

3.断开连接后主动断开放为什么要维持2MSL的TIME_WAIT状态?

回答:

(1)为了实现TCP全双工连接的可靠释放

我们还是假设一种情况,假设客户端发送了FIN,服务器也回送了确认报文,然后服务器没有数据要传送给客户端,所以服务器发送FIN给客户端,客户端收到以后就马上给服务器回送确认报文,如果客户端不维持TIME_WAIT状态,

这时客户端就TCP就会认为连接已经断开,但是不幸发生了,客户端回送给服务器的确认报文在网络中丢失了,服务器在MSL时间后还是没有收到客户端发回送的确认报文就会重新发送FIN报文,这时客户端TCP认为自己并没有半关闭的连接,所以就回送RST报文,这个报文被服务器解释成一个错误,然而这只是正常关闭连接的过程,而且这也不符合TCP可靠的个性~

(2)允许老的重复分节在网络中消逝

我们再次做出假设,如果没有TIME_WAIT状态。假设服务器在IP为192.168.2.3 端口号8888上监听,客户端使用IP为192.168.3.4端口号为9999与服务器建立了连接,客户端向服务器发送了一个消息,但是这个消息因为网络原因延迟了一段时间(小于MSL),此时客户端迅速关闭连接,并迅速以相同的IP和端口与服务器建立连接(整个过程不超过MSL),这时,上一次连接中客户端发送的消息到达了服务器(不要忘记我们假设没有TIME_WAIT状态),服务器收到消息以后对客户的消息做出了回馈,事实上,我们知道这不是客户端第二次连接时发送的消息。如果没有TIME_WAIT状态,TCP可能就不在可靠了


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值