孙宇的技术专栏 大数据/机器学习

TCP三次握手/四次挥手

2013-03-29

阅读:


三次握手

所谓三次握手,是指建立一个TCP连接时需要客户端和服务器总共发送三个包

三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号并交换TCP窗口大小信息。步骤如下:

  1. 报文一:客户端发送一个SYN标志位置1的报文到服务器。指明客户打算连接的服务器的端口,以及初始化序号,保存在包头的序列号字段里。
  2. 报文二:客户端回应客户端,返回一个SYN标志位和ACK标志均为1的报文,表示对刚才这个 SYN 报文的回应,同时将 SYN 给客户端,询问客户端是否准备好进行通信。
  3. 报文三:客户端再次回应服务端一个 ACK 报文。SYN标识为0,ACK标识为1。

报文: 网络中交换与传输的数据单元。它包含要发送的完整数据信息,传输过程中会不断地封装成分组,包,帧来传输。封装的方式就是添加一些信息段,报头。

一段消息从 A 传到 B,要经过很多个路由器。任意两个路由器之间的传递,它们的报头都是不一样的,都需要对内容进行重新封装。

四次挥手

TCP的连接的断开需要发送四个包,因此称为四次挥手。客户端或服务器均可主动发起挥手动作。

由于 TCP 连接是全双工的,因为每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务时,就发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动了,一个 TCP 连接在收到一个 FIN 后仍能发送数据。首先关闭的一方将执行主动关闭,而另一方执行被动关闭。

过程如下:

  1. 报文四:客户端发送一个 FIN, 用来关闭客户到服务器的数据发送。
  2. 报文五:服务器收到 FIN, 回发一个 ACK, 确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
  3. 报文六:服务器关闭客户端的连接,发送一个FIN给客户端。
  4. 报文七:客户端回ACK报文确认,并将确认序号设置为收到序号加1。

为什么是三次握手四次挥手

这是因为服务端的LISTEN状态下的socket当收到SKY报文的简历连接的请求后,它可以把ACK和SYN放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,他仅仅表示对方没有数据发送给你了,但未必你的所有数据都全部发送给对方了,所以你可能不是马上会关闭socket,即你可能还会发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以这里的ACK和FIN报文多情况下都是分开发送的。

2MSL

MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

IP 头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个IP数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。

当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,并停留 2MSL(Max Segment LifeTime)。

这样的目的是:

双方都同意关闭连接,而且挥手的 4 个报文也都协调和发送完毕,按理可以到 CLOSED 状态。但网络不一定可靠。无法保证最后一次发送的 ACK 真实的被对方收到,而是单纯的发出了。比如对方处于 LAST_ACK 状态下的 SOCKET 可能会因为超时未收到 ACK 报文而重发 FIN。TIME_WAIT 就是用来等这个超时重发的。

如果服务器中 TIME_WAIT 过多,服务器会被拖死。我们可以通过修改内核参数减少该参数的数量:

[root@localhost ~]# vi /etc/sysctl.conf 

在最后加上:

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.ip_local_port_range=1024 65000

让变更生效:

[root@localhost ~]# /sbin/sysctl -p

各种连接状态

服务器中查看连接状态命令:

[root@ttt ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'


LAST_ACK 9
SYN_RECV 11
ESTABLISHED 74
FIN_WAIT1 14
FIN_WAIT2 11
TIME_WAIT 315

各状态的含义:

CLOSED: 还未建立连接或已经断开

LISTEN: 服务器正在监听,可以接受连接

SYN_RECV: 一个连接请求已经到达,等待确认.接收到 SYN 报文,要返回 SYN 和 ACK ,然后会进入 ESTABLISHED 状态。

SYN_SEND: 客户端 SOCKET 执行连接时,发送SYN,然后进入 SYN_SEND.表示客户端已经发送了 SYN.这个状态会很短,因为服务端接收到 SYN 后马上会返回 SYN 和 ACK,然后就进入ESTABLISHED 了。

ESTABLISHED: 正常数据传输

FIN_WAIT1: 当连接处在 ESTABLISHED 时,客户想主动关闭连接,就会向对方发送 FIN.然后进入 FIN_WAIT1.对方收到 FIN 后会回应 ACK,然后进入 FIN_WAIT2。所以FIN_WAIT1很难碰到,就象上面的 SYN_RECV 和 SYN_SEND 一样。

FIN_WAIT2: 另一边已同意释放连接

CLOSING: 两边同时尝试关闭连接。该情况很特殊,正常情况是:你发送 FIN, 然后收到对方的 ACK, 然后再收到对方的 FIN. 但对方的 FIN 却在 ACK 前到了。

TIME_WAIT: 收到对方的 FIN 报文,且已经发送 ACK.就等 2MSL 后即可回到 CLOSED 可用状态。

LAST_ACK: 被动关闭的一方在发送 FIN 后,等待对方的 ACK.什么时候接收到 ACK, 什么时候进入 CLOSED 状态。


上一篇 Memcached

下一篇 MySQL 主从复制

评论

文章