您的位置:首页 > 理论基础 > 计算机网络

TCP的三次握手四次挥手

2015-09-23 11:41 204 查看

一。三次握手

1.wireshark 抓包



2.TCP报文手部



注意标志位:

1).同步 SYN = 1 表示这是一个连接请求或连接接受报文。

2).只有当 ACK = 1 时确认号字段才有效。当 ACK = 0 时,确认号无效。

3).FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。

3.连接示意



二。四次挥手

1.知所以然

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)

放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部

发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意

现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

  更明了的回答:由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一

个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行

关闭的一方将执行主动关闭,而另一方执行被动关闭。

2.图示



3. 2MSL(Maximum Segment Lifetime)存在的理由

TCP的TIME_WAIT状态也称为2MSL等待状态

(1)让4次握手关闭流程更加可靠

   4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个

2MSL,则有更大的机会让丢失的ACK被再次发送出去。

(2)防止lost duplicate对后续新建正常链接的传输造成破坏。

  lost duplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在路由器A,B,C之间做循环的

跳转。IP头部有个TTL,限制了一个包在网络中的最大跳数,因此这个包有两种命运,要么最后TTL变为0,在网络中消失;要么TTL在变为0之

前路由器路径收敛,它凭借剩余的TTL跳数终于到达目的地。但非常可惜的是TCP通过超时重传机制在早些时候发送了一个跟它一模一样的包,

并先于它达到了目的地,因此它的命运也就注定被TCP协议栈抛弃。

  另外一个概念叫做incarnation connection,指跟上次的socket pair一摸一样的新连接,叫做incarnation of previous connection。

lost duplicate加上incarnation connection,则会对我们的传输造成致命的错误。大家都知道TCP是流式的,所有包到达的顺序是不一致的,

依靠序列号由TCP协议栈做顺序的拼接;假设一个incarnation connection这时收到的seq=1000, 来了一个lost duplicate为seq=1000,

len=1000, 则tcp认为这个lost duplicate合法,并存放入了receive buffer,导致传输出现错误。通过一个2MSL状态,确保所有的

lost duplicate都会消失掉,避免对新连接造成错误。

4.2MSL状态为什么设计在主动关闭这一方
(1)发最后ack的是主动关闭一方
(2)只要有一方保持TIME_WAIT状态,就能起到避免incarnation connection在2MSL内的重新建立,不需要两方都有

三。TCP连接出现大量TIME_WAIT的解决办法

一个TCP/IP连接断开以后,会通过TIME_WAIT的状态保留一段时间,时间过了才会释放这个端口,当端口接受的频繁请求数量过多的时候,

就会产生大量的TIME_WAIT状态的连接,这些连接占着端口,会消耗大量的资源。面对这种情况可以通过修改TCP/IP的内核参数,来及时

的处理这些状态。

netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

执行该命令如果出现了大量的 TIME_WAIT 连接数目的话,如下:
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18000

vi /etc/sysctl.conf

然后,在这个文件中,加入下面的几行内容:

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30

最后输入下面的命令,让内核参数生效:

/sbin/sysctl -p


简单的说明下,上面的参数的含义:

net.ipv4.tcp_syncookies = 1

表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse = 1

表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1

表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;

net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间。

此外,如果你的连接数本身就很多,我们可以再优化一下TCP/IP的可使用端口范围,进一步提升服务器的并发能力。

依然是往上面的参数文件中,加入下面这些配置:

net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000

这几个参数,建议只在流量非常大的服务器上开启,会有显著的效果。这几个参数的含义如下:

net.ipv4.tcp_keepalive_time = 1200

表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。

net.ipv4.ip_local_port_range = 10000 65000

表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000。

将最低值设的太低,否则可能会占用掉正常的端口

net.ipv4.tcp_max_syn_backlog = 8192

表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_max_tw_buckets = 5000

表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。

默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接

字数量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: