一文带你搞定TCP挥手 tcpip握手挥手

摘要

  1. TCP断开连接
  2. TIME_WAIT
  3. TIME_WAIT优化
  4. TCP保活
  5. Sokcet编程

TCP断开连接

TCP断开连接,需要经历四次挥手,通信的双方都可主动断开连接,断开连接通信的双方占用的资源将会被释放。

  1. 客户端会发送一个FIN报文给服务端,然后进入FIN_WAIT_1状态
  2. 服务端在收到FIN报文后,会回复客户端段一个ACK报文,然后进入CLOSED_WAIT状态
  3. 客户端在收到服务端的ACK报文以后会进入FIN_WAIT_2状态
  4. 服务端在处理完历史数据以后会发送FIN报文给客户端,然后进入LAST_ACK状态
  5. 客户端在收到服务端的FIN报文以后,会发送一个ACK报文给服务端,然后进入TIME_WAIT状态
  6. 服务器在收到ACK报文以后,就会真正的关闭连接,进入CLOSED状态
  7. 客户端在经过2MSL时间后,也会自动关闭连接进入CLOSED状态

为什么回收需要四次

原因是客户端在主动发起FIN报文以后仅表示客户端不再主动发送数据了但是还可以接收数据。服务器在响应ACK报文以后,还有可能有数据还在处理且需要发送给客户端,因此当服务器处理完这些数据以后才能发送FIN报文表示同意关闭连接。

因此服务端的ACK和FIN报文需要分开发送,挥手也就变成了4次。

什么是MSL和TTL

TTL是IP头部中的一个字段,是指IP数据报可以经过的最大路由数,每经过一个路由器都需要减1,当TTL值为0时数据报就会被丢弃,同时发送ICMP报文给源主机。TTL的单位是路由跳数。

MSL是报文在网络中存在的最长时间,超过该时间就会被丢弃。

为什么TIME_WAIT需要经历2MSL后才可以变为CLOSED

网络中存在的发送方数据包,首先需要发送给服务端,服务端在处理完以后又会将相应发送给客户端,所以总共需要2个倍的时间。

2MSL的时间是从客户端接收到FIN报文并且发送ACK报文时开始的。如果此时ACK报文没有被服务端接收到触发了服务端的超时重传,客户端又再次收到了FIN报文,那么2MSL将重新开始计时。

LINUX中默认一个MSL是30s,也就是说TIME_WAIT的时间是60s。

TIME_WAIT

为什么需要TIME_WAIT状态

主动发起连接中断的一方需要有TIME_WAIT状态,主要是以下原因:

  • 防止具有相同四元组的旧数据包被收到
  • 保证最后一次ACK报文能被被动关闭连接的一方收到,也就是保证被动关闭连接的一方能被正确关闭。

防止旧连接的数据包被收到

假设没有TIME_WAIT状态,如果有相同的端口的TCP连接被服用后,上图中被延迟SEQ=301的数据包抵达了客户端,客户端是有可能正常接收该报文的,此时就会产生数据错乱现象。

但通过2MSL的等待时间,通信双方的数据包都可以在网络中消失,新的数据包一定是新连接的。

保证连接正确关闭

通过等待2MSL的时间确保最后一次ACK报文被被动断开连接的一方收到,从而正常关闭。

上图如果服务端没有收到最后一个ACK报文会处于LAST_ACK状态,如果此时客户端发起了一个新的SYN报文请求建立连接,服务端会发送RST报文给客户端,连接建立失败。

但是通过等待2MSL的时间会解决上述问题,因为假设服务端没有收到最后一次ACK报文,会触发超时重传重新发送FIN报文并等待新的ACK报文。客户端在收到新的FIN报文时会重新发送ACK报文并刷新2MSL的计时,最终能够保证服务端的连接能够正常关闭。

TIME_WAIT过多的弊端

服务器如果有TIME_WAIT状态的连接,说明TCP连接的断开是由服务端发起的,此时如果TIME_WAIT的连接过多,将会出现以下问题:

  • 内存资源占用
  • 端口资源占用,假设端口被占满,将无法建立新的连接
# 该参数用于指定开放的端口资源,默认是32768-61000
net.ipv4.ip_local_port_range

TIME_WAIT优化

TIME_WAIT的优化主要有以下几种方式,每种方式都有利有弊:

  • 打开net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps选项
  • net.ipv4.tcp_max_tw_buckets
  • 应用程序使用SO_LINGER,应用强制使用RST关闭

打开net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps选项

参数开启以后,可以复用处于TIME_WAIT的Socket给新的连接使用。

tcp_tw_reuse的功能只能用于连接发起方,开启该参数以后,在调用connect函数时,内核会随机找一个time_wait超过1s的连接给新的连接复用。

net.ipv4.tcp_timestamp默认开启,表示打开对TCP时间戳的支持。时间戳字段存储在TCP头部的选项字段中,用于记录TCP发送方的时间戳和从对端接收到的最新时间戳。

net.ipv4.tcp_max_tw_buckets

当系统中的TIME_WAIT的连接数超过该项的值时,系统那个会将后面TIME_WAIT的连接重置,不推荐使用。

程序使用SO_LINGER

通过设置Sokcet的一些选项,来影响close方法的一些行为。

如果SO_LINGER中的onoff为非0,并且linger为0,调用close方法以后会立即发送一个RST报文给对方,TCP连接会直接跳过四次握手关闭。也过于暴力不推荐。

TCP保活机制

在某个时间段内,如果TCP连接上无任何活动,TCP保活机制开始生效,每隔一段时间就会发送一个探测报文,如果连续几个探测报文都没有收到响应,则认为TCP连接已死,系统内核会将错误信息通知给应用程序。

# 用于控制保活时间,如果7200s内没有活动,则会启动保活机制
net.ipv4.tcp_keepalive_time=7200

# 保活机制每次检测间隔为75s
net.ipv4.tcp_keepalive_intvl=75

# 如果9次探测无响应,则认为对端不可答,中断本次连接
net.ipv4.tcp_keepalive_probes=9

上述三个都是Linux中的默认值,也就是说Linux操作系统中至少经过2小时11分15秒才可以发现一个死亡连接。

Socket编程

public ServerSocket(int port, int backlog) throws IOException {
    this(port, backlog, null);
}

Java中的ServerSokcet的初始化方法中有一个backlog参数,该参数在Linux2.2以前代表SYN队列大小,但是在Linux 2.2以后就是全连接队列的大小(accept队列的大小)。

  • 半连接队列(SYN队列):接收SYN请求,处于SYN_RCVD状态的连接
  • 全连接队列(Accept队列):完成三次握手处于ESTABLISHED状态的连接

Socket的一些连接操作对应的tcp连接步骤

  1. Socket在调用connect方法时,会发送SYN包给服务端,服务端会接收到到SYN报文,并且服务端会半连接队列里初始化一个连接。
  2. 服务端在处理完以后会发送ACK+SYN报文给客户端,客户端收到以后切实是就是connect方法的返回,同时客户端也需要对服务端的SYN报文进行应答。
  3. 服务端收到ACK报文以后,半连接队里的连接会被转移到全连接队列中,此时accept方法会成功拿到连接并生成一个Socket(这个就是传输时的Socket,不是监听Socket)。

close方法对应的TCP四次挥手

  1. 客户端调用close方法,会发送一个FIN报文给服务端
  2. 服务端收到FIN报文时,TCP协议栈会为该包插入一个文件结束符EOF到接收缓冲区,应用程序可以通过read方法获取到该文件结束符。**EOF会被放在所有的数据之后。**服务端会进入CLOSED_WAIT状态。
  3. 服务端处理完所有的数据以后,会读取到EOF,此时会调用close方法关闭Socket,然后发送一个FIN包进入LAST_ACK状态。
  4. 后面的其实就是TCP最终断开连接。

相关文章

3000字讲讲TCP协议,握手挥手不是你想的那么简单

专注于Java领域优质技术,欢迎关注作者: tobe 来自:tobe的呓语上一次讲了 UDP 协议,从这次开始,就要讲 TCP 协议了,因为 TCP 协议涉及到的东西很多,一篇文章概括不完,所以我把...

Java编程-TCP JAVA编程手机软件

1.1. Java的TCP面向连接, 数据安全, 区分服务器端和客户端.TCP分为Socket(客户端)和ServerSocket(服务端)需要分别建立客户端和服务器端客户端和服务端建立连接后,通过S...

4000 字详解TCP超时与重传,看完没收获算我输

专注于Java领域优质技术,欢迎关注作者: tobe 来自:tobe的呓语上一篇介绍 TCP 的文章「TCP 三次握手,四次挥手和一些细节」反馈还不错,还是蛮开心的,这次接着讲一讲关于超时和重传那一部...

用 Wireshark 让你看见 TCP 到底是什么样

前言当你看到这篇文章时,你只能看到已经渲染好的文字和图像,而网络数据的交互对我们来说,却是看不见的,所以学习计算机网络原理的时候就会觉得非常的抽象,这一度让我苦恼。而且网络数据交换真实的模样,到底是不...

一文带你搞定TCP流量控制 tcp流量控制算法

摘要理想的流量控制实际的流量控制窗口关闭糊涂窗口综合征理想的流量控制什么是流量控制?流量控制就是发送方不能无脑的给接收方发送数据,它需要根据接收方的处理能力来发送数据。理想下的流量控制?理想意味着在实...

有关TCP协议,这是我看过讲的最清楚的一篇文章了!

TCP 协议是网络传输中至关重要的一个协议,它位于传输层。向上支持 FTP、TELNET、SMTP、DNS、HTTP等常见的应用层协议,向下要与网络层的 IP 协议相互配合,实现可靠的网络传输。分层网...