动图图解:没有accept,能建立TCP连接吗

图片

每个listen Socket都有一个全连接和半连接队列

半连接队列、全连接队列是什么

图片

半连接队列和全连接队列

  • 半连接队列(SYN队列),服务端收到第一次握手后,会将sock加入到这个队列中,队列内的sock都处于SYN_RECV 状态。

  • 全连接队列(ACCEPT队列),在服务端收到第三次握手后,会将半连接队列的sock取出,放到全连接队列中。队列里的sock都处于 ESTABLISHED状态。这里面的连接,就等着服务端执行accept()后被取出了。

看到这里,文章开头的问题就有了答案,建立连接的过程中根本不需要accept() 参与, 执行accept()只是为了从全连接队列里取出一条连接。

我们把话题再重新回到这两个队列上。

虽然都叫队列,但其实全连接队列(icsk_accept_queue)是个链表,而半连接队列(syn_table)是个哈希表

图片

半连接全连接队列的内部结构

为什么半连接队列要设计成哈希表

先对比下全连接里队列,他本质是个链表,因为也是线性结构,说它是个队列也没毛病。它里面放的都是已经建立完成的连接,这些连接正等待被取走。而服务端取走连接的过程中,并不关心具体是哪个连接,只要是个连接就行,所以直接从队列头取就行了。这个过程算法复杂度为O(1)

半连接队列却不太一样,因为队列里的都是不完整的连接,嗷嗷等待着第三次握手的到来。那么现在有一个第三次握手来了,则需要从队列里把相应IP端口的连接取出,如果半连接队列还是个链表,那我们就需要依次遍历,才能拿到我们想要的那个连接,算法复杂度就是O(n)。

而如果将半连接队列设计成哈希表,那么查找半连接的算法复杂度就回到O(1)了。

因此出于效率考虑,全连接队列被设计成链表,而半连接队列被设计为哈希表。

怎么观察两个队列的大小

查看全连接队列

# ss -lnt

State      Recv-Q Send-Q     Local Address:Port           Peer Address:Port

LISTEN     0      128        127.0.0.1:46269              :

通过ss -lnt命令,可以看到全连接队列的大小,其中Send-Q是指全连接队列的最大值,可以看到我这上面的最大值是128Recv-Q是指当前的全连接队列的使用值,我这边用了0个,也就是全连接队列里为空,连接都被取出来了。

当上面Send-QRecv-Q数值很接近的时候,那么全连接队列可能已经满了。可以通过下面的命令查看是否发生过队列溢出

# netstat -s | grep overflowed

4343 times the listen queue of a socket overflowed

上面说明发生过4343次全连接队列溢出的情况。这个查看到的是历史发生过的次数

如果配合使用watch -d 命令,可以自动每2s间隔执行相同命令,还能高亮显示变化的数字部分,如果溢出的数字不断变多,说明正在发生溢出的行为。

# watch -d ‘netstat -s | grep overflowed’

Every 2.0s: netstat -s | grep overflowed                                Fri Sep 17 09:00:45 2021

4343 times the listen queue of a socket overflowed

查看半连接队列

半连接队列没有命令可以直接查看到,但因为半连接队列里,放的都是SYN_RECV 状态的连接,那可以通过统计处于这个状态的连接的数量,间接获得半连接队列的长度。

# netstat -nt | grep -i ‘127.0.0.1:8080’ | grep -i ‘SYN_RECV’ | wc -l

0

注意半连接队列和全连接队列都是挂在某个Listen socket上的,我这里用的是127.0.0.1:8080,大家可以替换成自己想要查看的IP端口

可以看到我的机器上的半连接队列长度为0,这个很正常,正经连接谁会没事老待在半连接队列里。

当队列里的半连接不断增多,最终也是会发生溢出,可以通过下面的命令查看。

# netstat -s | grep -i “SYNs to LISTEN sockets dropped”

26395 SYNs to LISTEN sockets dropped

可以看到,我的机器上一共发生了26395次半连接队列溢出。同样建议配合watch -d 命令使用。

# watch -d ‘netstat -s | grep -i “SYNs to LISTEN sockets dropped”’

Every 2.0s: netstat -s | grep -i “SYNs to LISTEN sockets dropped”       Fri Sep 17 08:36:38 2021

26395 SYNs to LISTEN sockets dropped

全连接队列满了会怎么样?

如果队列满了,服务端还收到客户端的第三次握手ACK,默认当然会丢弃这个ACK。

但除了丢弃之外,还有一些附带行为,这会受 tcp_abort_on_overflow 参数的影响。

# cat /proc/sys/net/ipv4/tcp_abort_on_overflow

0

  • tcp_abort_on_overflow设置为 0,全连接队列满了之后,会丢弃这个第三次握手ACK包,并且开启定时器,重传第二次握手的SYN+ACK,如果重传超过一定限制次数,还会把对应的半连接队列里的连接给删掉。

图片

tcp_abort_on_overflow为0

  • tcp_abort_on_overflow设置为 1,全连接队列满了之后,就直接发RST给客户端,效果上看就是连接断了。

这个现象是不是很熟悉,服务端端口未监听时,客户端尝试去连接,服务端也会回一个RST。这两个情况长一样,所以客户端这时候收到RST之后,其实无法区分到底是端口未监听,还是全连接队列满了

图片

tcp_abort_on_overflow为1

半连接队列要是满了会怎么样

一般是丢弃,但这个行为可以通过 tcp_syncookies 参数去控制。但比起这个,更重要的是先了解下半连接队列为什么会被打满。

首先我们需要明白,一般情况下,半连接的"生存"时间其实很短,只有在第一次和第三次握手间,如果半连接都满了,说明服务端疯狂收到第一次握手请求,如果是线上游戏应用,能有这么多请求进来,那说明你可能要富了。但现实往往比较骨感,你可能遇到了SYN Flood攻击

所谓SYN Flood攻击,可以简单理解为,攻击方模拟客户端疯狂发第一次握手请求过来,在服务端憨憨地回复第二次握手过去之后,客户端死活不发第三次握手过来,这样做,可以把服务端半连接队列打满,从而导致正常连接不能正常进来。

图片

syn攻击

那这种情况怎么处理?有没有一种方法可以绕过半连接队列

有,上面提到的tcp_syncookies派上用场了。

# cat /proc/sys/net/ipv4/tcp_syncookies

1

当它被设置为1的时候,客户端发来第一次握手SYN时,服务端不会将其放入半连接队列中,而是直接生成一个cookies,这个cookies会跟着第二次握手,发回客户端。客户端在发第三次握手的时候带上这个cookies,服务端验证到它就是当初发出去的那个,就会建立连接并放入到全连接队列中。可以看出整个过程不再需要半连接队列的参与。

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

总结

一般像这样的大企业都有好几轮面试,所以自己一定要花点时间去收集整理一下公司的背景,公司的企业文化,俗话说「知己知彼百战不殆」,不要盲目的去面试,还有很多人关心怎么去跟HR谈薪资。

这边给大家一个建议,如果你的理想薪资是30K,你完全可以跟HR谈33~35K,而不是一下子就把自己的底牌暴露了出来,不过肯定不能说的这么直接,比如原来你的公司是25K,你可以跟HR讲原来的薪资是多少,你们这边能给到我的是多少?你说我这边希望可以有一个20%涨薪。

最后再说几句关于招聘平台的,总之,简历投递给公司之前,请确认下这家公司到底咋样,先去百度了解下,别被坑了,每个平台都有一些居心不良的广告党等着你上钩,千万别上当!!!

Java架构学习资料,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书。
在这里插入图片描述

多少?你说我这边希望可以有一个20%涨薪。

最后再说几句关于招聘平台的,总之,简历投递给公司之前,请确认下这家公司到底咋样,先去百度了解下,别被坑了,每个平台都有一些居心不良的广告党等着你上钩,千万别上当!!!

Java架构学习资料,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书。
[外链图片转存中…(img-YBfT7Fpt-1710413083920)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值