前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP的十一种状态与三次握手分析

TCP的十一种状态与三次握手分析

作者头像
xcywt
发布2022-05-09 14:17:05
3130
发布2022-05-09 14:17:05
举报
文章被收录于专栏:xcywt

我们知道TCP是面向连接的,我们只知道有连接断开,其实内部还有一些比较复杂的状态。去了解各个状态之间的切换有助于我们更加深入的了解TCP。下面我们就来分析各个状态。

1、如下图示(图源百度)图中显示出了10种状态。

我们假定断开时是client主动断开的。 对于server来说状态有:closed -> listen -> syn_recv -> enstablished -> close_wait -> last_ack -> closed 对于client来说状态有:closed -> syn_send -> enstablished -> fin_wait1 -> fin_wait2 -> time_wait 2.结合三次握手进行分析状态 我们知道三次握手的这样:  client 发送 syn x到server server 回复syn y和ack x+1 client再回复 ack y+1 下面分析上面三步与状态的关系: 1)首先,刚创建的socket都是closed状态,server调用listen之后进入listen状态 2)接着、客户端调用connnect。(TCP协议会完成三次握手,client发送第一个syn之后就进入syn_send状态。与此同时,server收到syn并回复syn和ack,server进入syn_recv状态) 3)之后、client和server都进入了enstablisted状态。之后就可以互相发送数据了。

关于TCP协议头中的确认号ack的理解可以参考:http://www.cnblogs.com/xcywt/p/8075623.html

关于Wireshark的理解可以参考:http://www.cnblogs.com/xcywt/p/8025113.html

结合Wireshark抓包分析三次握手:

 这里设置的过滤器,先清空当前捕获的包,在浏览器打开博客园。

假设TCPa -> TCPb

第一次:如下图,发送一个请求 syn,序号为0

第二次:B回复,发送syn,ack为0+1

第三次,A回复,ack = y + 1。其中y为之前B发送过来的序号,这里过来的序号的0,所以ack = 1;

3.结合断开时四次握手进行分析状态

如图(图源百度,侵删)

我们知道四次握手是这样的(假定是client先close 的): client调用close。TCP协议会发送FIN x给server server收到FIN x之后,会回复ack x+1 接着、server调用close,给客户端发送FIN y 最后,客户端回复ack y+1 分析与状态的关系: 1)client调用close,发送了FINx。client进入fin_wait1状态。server收到并回复ack,server进入close_wait状态。然后client会收到ack,进入fin_wait2状态 2)server接着调用close,给client发送了fin,server则进入了了last_ack状态。 3)client收到FIN 之后,回复ack。client进入time_wait状态。server收到ack之后,进入closed状态。 (client在保持了2个MSL之后就进入closed状态) 4.注意事项 1)client进入time_wait状态之后,会保持在这个状态2MSL。目的是为了确保发送过去的ack可以被收到(因为后面已经没有数据可以发送了)。 2)连接过程是状态的改变,促使状态的改变是用户的调用。所以切换状态不一定是用户的调用。(比如,server进入close_wait状态,纯粹是TCP协议做好的,用户并没有调用什么接口) 3)关于退出时的分析,存在一个主动一个被动关系。上面分析的client主动,则client会出现fin_wait1、fin_wait2、time_wait状态。server会出现close_wait、last_ack状态。 如果是server主动断开的,则关系刚刚反过来了。server先进入fin_wait1状态,然后是fin_wait2状态。后面整个就反过来了。 5.关于closing状态的出现(这里就是第十一种状态) 通过上面的分析我们知道,client主动退出时,先给server发送了一个FIN。接着会收到一个ack确认这个FIN。 如果没收到ack,而是收到server发来的FIN y。那么这时候则进入closing状态。 这种情况是怎么出现的呢:那就是双方几乎同时closer一个socket。这是双方都正在关闭socket连接。这种情况出现的几率很小 6.为什么连接需要三次握手,断开需要四次握手。 首先我们知道,TCP协议是去全双工的。可以在发送的同时进行接收数据。 假定是主机A和主机B进行通信,断开时是A主动断开的。 1)三次握手:第一次握手表明A可以发数据给B。但是无法保证B发给A的数据可以被收到。所以B也需要发送SYN给A,A对它进行回应,才保证了B也可以发数据给A。 个人理解可以把三步拆分为四步理解: a)主机A给B发送SYN b)主机B回复ack --- 这时表明A可以发数据给B c)主机B发送SYN给A d)主机A回复ack --- 这时表明B也可以发送数据给A 只不过协议中,把中间两步放在一步进行了。 2)四次握手,就像下面这样理解: a)主机A给B发送FIN,表示对B说“我要断开了” b)主机B回复ack进行确认,表示对A说“嗯,我知道了,你可以断开了” c)然后B发送FIN给A,表示对A说“A,我也要断开了” d)A回复ack进行确认,表示对B说:“嗯,知道了,你断开吧” 前两步对A进行断开,后两步对B进行断开。 那么为什么不能把中间两步进行合并呢,因为无法保证被断开的一方的数据已经传送完毕了。 就拿上面的例子来说,假如A断开了通知B,但是B还有数据没有发送完毕,如果立即断开(调用close发送FIN),就无法保证数据的可靠性。 如果等数据发送完毕再将fin和ack一起发过去,n那么A就会长时间处于fin_wait1状态。这样就比较不好了。 实际情况中我们可能会在server忘记关闭客户端的socket。那么client就会一直处于fin_wait2状态,越来越多的fin_wait2状态会导致系统崩溃。所以我们需要在编程中要注意在什么情况下要关闭双方的socket。

7.其他知识 什么时候会收到SIGPIPE这个信号呢? 当server关闭一个连接之后,client接着发送数据,第一次发送会收到一个RST的响应。如果接着发送则系统会发出一个SIGPIPE信号给client。 系统默认的处理是将应用程序退出。实际编程中,我们可以捕获这个信号,让应用程序不退出

 如下(伪代码):

代码语言:javascript
复制
#include"signal.h"
void sig_recvpipe(int sig)
{
}

int main()
{
    ......
    signal(SIGPIPE, sig_recvpipe);
    ......
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档