TCP三次握手原理,你真的理解吗

阿里妹导读:最近,阿里中间件小哥哥蛰剑碰到一个问题——clint端连接服务器总是抛异常。在反复定位分析、并查阅各种资料文章搞懂后,他发现没有文章把这两个队列以及怎么观察他们的指标说清楚。

因此,蛰剑写下这篇文章,希望借此能把这个问题说清楚。欢迎大家一起交流探讨。

问题描述

场景:JAVA的clint和srvr,使用sockt通信。srvr使用NIO。

1.间歇性得出现clint向srvr建立连接三次握手已经完成,但srvr的slctor没有响应到这连接。

2.出问题的时间点,会同时有很多连接出现这个问题。

3.slctor没有销毁重建,一直用的都是一个。

4.程序刚启动的时候必会出现一些,之后会间歇性出现。

分析问题正常TCP建连接三次握手过程:

步:clint发送syn到srvr发起握手;

第二步:srvr收到syn后回复syn+ack给clint;

第三步:clint收到syn+ack后,回复srvr一个ack表示收到了srvr的syn+ack(此时clint的端口的连接已经是stablishd)。

从问题的描述来看,有点像TCP建连接的时候全连接队列(accpt队列,后面具体讲)满了,尤其是症状2、4.为了证明是这个原因,马上通过ntstat-s

grp"listn"去看队列的溢出统计数据:

反复看了几次之后发现这个ovrflowd一直在增加,那么可以明确的是srvr上全连接队列一定溢出了。

接着查看溢出后,OS怎么处理:

tcp_abort_on_ovrflow为0表示如果三次握手第三步的时候全连接队列满了那么srvr扔掉clint发过来的ack(在srvr端认为连接还没建立起来)

为了证明客户端应用代码的异常跟全连接队列满有关系,我先把tcp_abort_on_ovrflow修改成1,1表示第三步的时候如果全连接队列满了,srvr发送一个rst包给clint,表示废掉这个握手过程和这个连接(本来在srvr端这个连接就还没建立起来)。

接着测试,这时在客户端异常中可以看到很多connctionrstbypr的错误,到此证明客户端错误是这个原因导致的(逻辑严谨、快速证明问题的关键点所在)。

于是开发同学翻看java源代码发现sockt默认的backlog(这个值控制全连接队列的大小,后面再详述)是50,于是改大重新跑,经过12个小时以上的压测,这个错误一次都没出现了,同时观察到ovrflowd也不再增加了。

到此问题解决,简单来说TCP三次握手后有个accpt队列,进到这个队列才能从Listn变成accpt,默认backlog值是50,很容易就满了。满了之后握手第三步的时候srvr就忽略了clint发过来的ack包(隔一段时间srvr重发握手第二步的syn+ack包给clint),如果这个连接一直排不上队就异常了。

但是不能只是满足问题的解决,而是要去复盘解决过程,中间涉及到了哪些知识点是我所缺失或者理解不到位的;这个问题除了上面的异常信息表现出来之外,还有没有更明确地指征来查看和确认这个问题。

深入理解TCP握手过程中建连接的流程和队列

(图片来源:







































白癜风的危害是什么
白癜风的问题



转载请注明:http://www.xxcyfilter.com/gailian/gailian/9887.html