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

本文详细解析TCP三次握手过程中全连接队列溢出的问题,通过实例分析了TCP建连接流程,解释了半连接队列和全连接队列的作用,并提供了观察队列状态的指标。通过调整backlog参数解决队列溢出导致的客户端连接异常,强调了理解这些概念对优化系统性能的重要性。
摘要由CSDN通过智能技术生成

640?wx_fmt=jpeg

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


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


问题描述


场景:JAVA的client和server,使用socket通信。server使用NIO。


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

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

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

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


分析问题


正常TCP建连接三次握手过程:


640?wx_fmt=png


  • 第一步:client 发送 syn 到server 发起握手;

  • 第二步:server 收到 syn后回复syn+ack给client;

  • 第三步:client 收到syn+ack后,回复server一个ack表示收到了server的syn+ack(此时client的56911端口的连接已经是established)。


从问题的描述来看,有点像TCP建连接的时候全连接队列(accept队列,后面具体讲)满了,尤其是症状2、4. 为了证明是这个原因,马上通过 netstat -s | egrep "listen" 去看队列的溢出统计数据:    


640?wx_fmt=png


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


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


640?wx_fmt=png


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


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


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


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


到此问题解决,简单来说TCP三次握手后有个accept队列,进到这个队列才能从Listen变成accept,默认backlog 值是50,很容易就满了。满了之后握手第三步的时候s

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值