欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TCP三次握手/四次挥手,TCP连接异常中断后,服务器的Socket应什么时候关闭

程序员文章站 2022-07-01 14:51:08
...

一、TCP三次握手/四次挥手

1. 三次握手

TCP三次握手/四次挥手,TCP连接异常中断后,服务器的Socket应什么时候关闭
第一次: 主机A 发送位码为syn=1,随机产生seq number=1234567 的数据包到服务器,

               主机B由SYN=1 知道,A 要求建立联机;
第二次: 主机B 收到请求后要确认联机信息, 向A 发送

                ack number=( 主机A 的seq+1),syn=1,ack=1,随机产生seq=7654321 的包
第三次:主机A 收到后检查ack number 是否正确,即第一次发送的seq number+1,以及位码 ack 是否为1,

               若正确,主机A 会再发送ack number=(主机B 的seq+1),ack=1,主机B 收到后确认seq 值与ack=1 则连接建立成功。

 

2. 四次挥手

TCP三次握手/四次挥手,TCP连接异常中断后,服务器的Socket应什么时候关闭
TCP 建立连接要进行三次握手,而断开连接要进行四次。这是由于TCP 的半关闭造成的。因为TCP 连
接是全双工的(即数据可在两个方向上同时传递)所以进行关闭时每个方向上都要单独进行关闭。这个单
方向的关闭就叫半关闭。当一方完成它的数据发送任务,就发送一个FIN 来向另一方通告将要终止这个
方向的连接。
1) 关闭客户端到服务器的连接:首先客户端A 发送一个FIN,用来关闭客户到服务器的数据传送,
然后等待服务器的确认。其中终止标志位FIN=1,***seq=u
2) 服务器收到这个FIN,它发回一个ACK,确认号ack 为收到的序号加1。
3) 关闭服务器到客户端的连接:也是发送一个FIN 给客户端。
4) 客户段收到FIN 后,并发回一个ACK 报文确认,并将确认序号seq 设置为收到序号加1。

首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
主机A 发送FIN 后,进入终止等待状态, 服务器B 收到主机A 连接释放报文段后,就立即
给主机A 发送确认,然后服务器B 就进入close-wait 状态,此时TCP 服务器进程就通知高
层应用进程,因而从A 到B 的连接就释放了。此时是“半关闭”状态。即A 不可以发送给
B,但是B 可以发送给A。此时,若B 没有数据报要发送给A 了,其应用进程就通知TCP 释
放连接,然后发送给A 连接释放报文段,并等待确认。A 发送确认后,进入time-wait,注
意,此时TCP 连接还没有释放掉,然后经过时间等待计时器设置的2MSL 后,A 才进入到
close 状态。

3.为什么会挥手次数比握手次数多?

这是由于TCP 的半关闭造成的。

因为TCP 连接是全双工的(即数据可在两个方向上同时传递)所以进行关闭时每个方向上都要单独进行关闭。这个单方向的关闭就叫半关闭。

当一方完成它的数据发送任务,就发送一个FIN 来向另一方通告将要终止这个方向的连接。

 

二、TCP连接异常中断后,服务器的Socket应什么时候关闭

1. TCP/IP可选特性Keepalive(默认关闭)

Keepalive特性需要在 setsockopt 里面把 SO_KEEPALIVE 标志设置为1,才会打开。

有3个参数,以linux为例,搜索keepalive相关的系统参数(sysctl -A |grep keepalive),通常会得到如下3个参数:
      net.ipv4.tcp_keepalive_intvl = 75              -- 间隔多少秒发一次嗅探包
      net.ipv4.tcp_keepalive_probes = 9           -- 嗅探包一共发几次
      net.ipv4.tcp_keepalive_time = 7200          -- TCP连接空闲多少秒后发嗅探包

3个参数组合起来表示:

    如果TCP连接2小时(7200秒)内没有数据传输,则发送嗅探包,每隔75秒发送一次,共重试9次。

    9次对方都没响应,则表明此连接已死。


一般服务器程序不会用到这个机制,而是把Keepalive放到业务层,自己实现Keepalive机制。这样做的好处是可以减少程序对特定协议的依赖,且发送给客户端的请求可以组合起来,在心跳包到来的时候一并返回给客户端。还有,开启Keepalive特性还有有一些其他方面的风险。

比如:

(1) cause perfectly good connections to break during transient Internet failures; 
(2)consume unnecessary bandwidth ("if no one is using the connection, who cares if it is still good?"); 
and (3) cost money for an Internet path that charges for packets.  (RFC1122)

因此,如果没打开TCP/IP的Keepalive特性,业务层又没有自己实现Keepalive,且未调用send/recv,那么连接会一直存在。

2. 不依赖 Keepalive 如何关闭

    正常情况下,如果一端关闭了socket,那么另一端会受到FIN包,因此是可以知道对端关闭的。
    异常情况下(如拔网线,用iptables封了端口),一端是不能收到对端的关闭通知的。可以通过send和recv检测,

    以linux为例:
         recv的man对返回值的介绍如下:
              RETURN VALUE
              These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer 
              has performed an orderly shutdown.
          即,recv返回0表示对端关闭。对于send,如果返回值为-1,且errno为ECONNRESET,表示对端关闭。

    因此,只要你在业务层有心跳机制,且正确处理了send/recv,那么对端断开你一定能得到通知

 

相关标签: socket tcpip