【2018-06-18】TCP的三次握手与四次挥手

📅 2026/7/18 15:37:36
【2018-06-18】TCP的三次握手与四次挥手
[历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2018-06-18 标题TCP的三次握手与四次挥手分类编程 标签TCPUDPTCP握手简单笔记TCP三次握手TCP四次挥手TCP头部11种状态参考链接《 https://blog.csdn.net/qzcsu/article/details/72861891 》《 https://blog.csdn.net/yanxiaolx/article/details/52123628 》《 https://www.cnblogs.com/qingergege/p/6603488.html 》TCP三次握手第一次握手客户端发送syn包**(synx)到服务器并进入SYN_SEND状态等待服务器确认第二次握手服务器收到syn包必须确认客户的SYNackx1同时自己也发送一个SYN包syny即SYNACK包此时服务器进入SYN_RECV状态第三次握手客户端收到服务器的SYNACK包向服务器发送确认包ACK(acky1)**此包发送完毕客户端和服务器进入ESTABLISHED状态完成三次握手。握手过程中传送的包里不包含数据三次握手完毕后客户端与服务器才正式开始传送数据。理想状态下TCP连接一旦建立在通信双方中的任何一方主动关闭连接之前TCP 连接都将被一直保持下去。确认号其数值等于发送方的发送序号1(即接收方期望接收的下一个序列号)。TCP四次挥手与建立连接的“三次握手”类似断开一个TCP连接则需要“四次挥手”。第一次挥手主动关闭方发送一个FIN用来关闭主动方到被动关闭方的数据传送也就是主动关闭方告诉被动关闭方我已经不会再给你发数据了(当然在fin包之前发送出去的数据如果没有收到对应的ack确认报文主动关闭方依然会重发这些数据)但是此时主动关闭方还可以接受数据。第二次挥手被动关闭方收到FIN包后发送一个ACK给对方确认序号为收到序号1与SYN相同一个FIN占用一个序号。第三次挥手被动关闭方发送一个FIN用来关闭被动关闭方到主动关闭方的数据传送也就是告诉主动关闭方我的数据也发送完了不会再给你发数据了。第四次挥手主动关闭方收到FIN后发送一个ACK给被动关闭方确认序号为收到序号1至此完成四次挥手。TCP的四次挥手过程简言之主动关闭方向被动关闭方发送不会再给你发数据了的信息被动关闭方对收到的主动关闭方的报文段进行确认被动关闭方向主动关闭方发送我也不会再给你发数据了的信息主动关闭方再次对被动关闭方的确认进行确认。TCP三次握手和四次挥手的全过程如下图TCP头部SYNSYN 1 表示这是一个连接请求或连接接受报文。在建立连接时用来进行同步序号个人理解是在建立连接的时候提醒对方记录本方的起始序号。当SYN1而ACK0时表明这是一个连接请求报文段。对方若是同意建立连接则应响应的报文段中使SYN1、ACK1。因此SYN1表示该报文是一个连接请求报文或者是一个连接请求接收报文。ACK确认号只有在该位设置为1的时候才生效当该位为0是表示确认号无效。TCP规定在TCP连接建立后所有传送的数据报文段ACK都必须设置为1。FIN当 FIN 1 时表明此报文段的发送方的数据已经发送完毕并要求释放连接。序号占4个字节它的范围在0-2^32-1序号随着通信的进行不断的递增当达到最大值的时候重新回到0在开始递增。TCP是面向字节流的在一个TCP连接中传送的字节流中的每一个字节都按照顺序编号。整个要传送的字节流的起始号必须在连接建立时设置。首部中的序列号字段指的是本报文段所发送的数据的第一个字节的序号。****例如一个报文序号是301而携带的数据共有100字节。则表示本次报文中的序号是301下一个报文的序号是401.重复一下每一个报文的序号是该报文包含的字节中第一个字节的编号。确认号占4个字节确认号是对下一个想要接受的字节的期望这里隐式确认了对上一个数据包的成功接收。如上例在成功接收了序号为301的数据包想要接收下一个数据包因为上个数据包包含100字节所以此时的确认号应该是401表示希望接收下一个序号是401的数据包。11种状态简单解释CLOSED初始状态表示TCP连接是“关闭着的”或“未打开的”。LISTEN 表示服务器端的某个SOCKET处于监听状态可以接受客户端的连接。SYN_RCVD 表示服务器接收到了来自客户端请求连接的SYN报文。在正常情况下这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态很短暂基本上用netstat很难看到这种状态除非故意写一个监测程序将三次TCP握手过程中最后一个ACK报文不予发送。当TCP连接处于此状态时再收到客户端的ACK报文它就会进入到ESTABLISHED 状态。SYN_SENT 这个状态与SYN_RCVD 状态相呼应当客户端SOCKET执行connect()进行连接时它首先发送SYN报文然后随即进入到SYN_SENT 状态并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送SYN报文。ESTABLISHED 表示TCP连接已经成功建立。FIN_WAIT_1 这个状态得好好解释一下其实FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时它想主动关闭连接向对方发送了FIN报文此时该SOCKET进入到FIN_WAIT_1 状态。而当对方回应ACK报文后则进入到FIN_WAIT_2 状态。当然在实际的正常情况下无论对方处于任何种情况下都应该马上回应ACK报文所以FIN_WAIT_1 状态一般是比较难见到的而FIN_WAIT_2 状态有时仍可以用netstat看到。FIN_WAIT_2 上面已经解释了这种状态的由来实际上FIN_WAIT_2状态下的SOCKET表示半连接即有一方调用close()主动要求关闭连接。注意FIN_WAIT_2 是没有超时的不像TIME_WAIT 状态这种状态下如果对方不关闭不配合完成4次挥手过程那这个 FIN_WAIT_2 状态将一直保持到系统重启越来越多的FIN_WAIT_2 状态会导致内核crash。TIME_WAIT 表示收到了对方的FIN报文并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSLMax Segment Lifetime最大分段生存期指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值RFC 1122建议是2分钟但BSD传统实现采用了30秒Linux可以cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值然后即可回到CLOSED 可用状态了。如果FIN_WAIT_1状态下收到了对方同时带FIN标志和ACK标志的报文时可以直接进入到TIME_WAIT状态而无须经过FIN_WAIT_2状态。这种情况应该就是四次挥手变成三次挥手的那种情况CLOSING 这种状态在实际情况中应该很少见属于一种比较罕见的例外状态。正常情况下当一方发送FIN报文后按理来说是应该先收到或同时收到对方的ACK报文再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后并没有收到对方的ACK报文反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢那就是当双方几乎在同时close()一个SOCKET的话就出现了双方同时发送FIN报文的情况这是就会出现CLOSING 状态表示双方都正在关闭SOCKET连接。CLOSE_WAIT 表示正在等待关闭。怎么理解呢当对方close()一个SOCKET后发送FIN报文给自己你的系统毫无疑问地将会回应一个ACK报文给对方此时TCP连接则进入到CLOSE_WAIT状态。接下来呢你需要检查自己是否还有数据要发送给对方如果没有的话那你也就可以close()这个SOCKET并发送FIN报文给对方即关闭自己到对方这个方向的连接。有数据的话则看程序的策略继续发送或丢弃。简单地说当你处于CLOSE_WAIT 状态下需要完成的事情是等待你去关闭连接。LAST_ACK 当被动关闭的一方在发送FIN报文后等待对方的ACK报文的时候就处于LAST_ACK 状态。当收到对方的ACK报文后也就可以进入到CLOSED 可用状态了。