由网络副手--寻路人于2017.05.12 20:01:00发布在服务器运维 TCP协议三次握手和四次挥手的原理剖析 阅读3400 评论0 喜欢1 TCP通过窗口滑动来进行流量控制 **窗口滑动的原理:** 连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端接收方发送的确认信息中包含了自己剩余的缓冲区尺寸,剩余的缓冲区空间的数量叫做窗口 ![1.png][1] 一、TPC三次握手 ![3.JPG][2] TCP三次握手目的为对主机层传输控制协议提供可靠的链接服务 传输过程中会有6中状态 1. SYN(synchronous建立联机) 2. ACK(acknowledgement 确认) 3. PSH(push传送) 4. FIN(finish结束) 5. RST(reset重置) 6. URG(urgent紧急) Sequence number(顺序号码) Acknowledge number(确认号码) 过程详解: (1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。 (2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。 (3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。 在三次握手后开始传输数据 二、TCP协议四次挥手 关闭连接 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。 ![4.png][3] (1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。 (2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。 (3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。 (4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。 、 四次握手即为四个阶段: 1.服务器读通道关闭 2.客户机写通道关闭 3.客户机读通道关闭 4.服务器写通道关闭 看下四次挥手中的客户端和服务端的状态变化 ![20170305155824486.png][4] 总结汇总: ![5.png][5] Linxu 统计服务器中各种状态数量: netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' ![5.jpg][6] 一、问题: TCP第四次挥手为什么要等待2MSL ? 这最主要是因为两个理由: 1、防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)。 2、可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。 二、CLOSE_WAIT,TIME_WAIT是什么状态,怎么产生的,对服务有什么影响,如何消除 ? TIME_WAIT 出现 通过上面可以知道客户端在发送最后一个确认包后进入timewait状态. 在访问量大的web中较明显 解决方案: 就是让服务器能够快速回收和重用那些TIME_WAIT的资源 vim /etc/sysctl.conf ---360-- #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 net.ipv4.tcp_tw_reuse = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 net.ipv4.tcp_tw_recycle = 1 #表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭 net.ipv4.tcp_syncookies = 1 #定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为1024,负载打的网站需要调整 net.core.somaxconn = 20480 #系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息 net.ipv4.tcp_max_orphans = 262144 #即file-max是设置 系统所有进程一共可以打开的文件数量,系统级别的,题外话,ulimit当前shell以及由它启动的进程的资源限制 fs.file-max = 1280000 #表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死 net.ipv4.tcp_max_tw_buckets = 180000 ---额外--- ##减少超时前的探测次数 net.ipv4.tcp_keepalive_probes=5 ##优化网络设备接收队列 net.core.netdev_max_backlog=3000 #对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,不应该大于255,默认值是5,对应于180秒左右时间 net.ipv4.tcp_syn_retries=2 #net.ipv4.tcp_synack_retries=2 #表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为300秒 net.ipv4.tcp_keepalive_time=1200 net.ipv4.tcp_orphan_retries=3 #表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间 net.ipv4.tcp_fin_timeout=30 #表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。 net.ipv4.tcp_max_syn_backlog = 4096 net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle的开启都是为了回收处于TIME_WAIT状态的资源。 net.ipv4.tcp_fin_timeout这个时间可以减少在异常情况下服务器从FIN-WAIT-2转到TIME_WAIT的时间。 net.ipv4.tcp_keepalive_*一系列参数,是用来设置服务器检测连接存活的相关配置。 修改完之后执行/sbin/sysctl -p让参数生效。 二、CLOSE_WAIT状态. 服务器程序代码出现问题了. 通过代码排查来,来找问题,大部分是资源没有释放导致. 举例说明Time_wait 和 close_wait 区别 服 务器A是一台爬虫服务器,它使用简单的HttpClient去请求资源服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完 资源后,服务器A会主动发出关闭连接的请求,这个时候就是主动关闭连接,服务器A的连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设 请求的资源服务器B上并不存在,那么这个时候就会由服务器B发出关闭连接的请求,服务器A就是被动的关闭了连接,如果服务器A被动关闭连接之后程序员忘了 让HttpClient释放连接,那就会造成CLOSE_WAIT的状态了。 [1]: http://blogimg.bravedu.com/2017/05/2317875040.png [2]: http://blogimg.bravedu.com/2017/05/1560967800.jpg [3]: http://blogimg.bravedu.com/2017/05/66612188.png [4]: http://blogimg.bravedu.com/2017/05/2404875530.png [5]: http://blogimg.bravedu.com/2017/05/3726617426.png [6]: http://blogimg.bravedu.com/2017/05/55398408.jpg 赞 1 分享 赏 您可以选择一种方式赞助本站 支付宝扫码赞助 BraveDu 署名: 网络副手~寻路人