| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> 从Linux源码看Socket(TCP)的listen及连接队列 -> 正文阅读 |
|
[网络协议]从Linux源码看Socket(TCP)的listen及连接队列 |
前言一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情。 今天就来从Linux源码的角度看下Server端的Socket在进行listen的时候到底做了哪些事情(基于Linux 3.10内核),当然由于listen的backlog参数和半连接hash表以及全连接队列都相关,在这一篇文章里也一块讲了。 Server端Socket需要Listen众所周知,一个Server端Socket的建立,需要socket、bind、listen、accept四个步骤。 代码如下:
首先我们通过socket系统调用创建了一个socket,其中指定了SOCK_STREAM,而且最后一个参数为0,也就是建立了一个通常所有的TCP Socket。在这里,我们直接给出TCP Socket所对应的ops也就是操作函数。 Listen系统调用好了,现在我们直接进入Listen系统调用吧。
注意,这边的listen调用是被glibc的INLINE_SYSCALL装过一层,其将返回值修正为只有0和-1这两个选择,同时将错误码的绝对值设置在errno内。 接下来,我们就进入Linux内核源码栈吧
值得注意的是,Kernel对于我们传进来的backlog值做了一次调整,让其无法>内核参数设置中的somaxconn。 C/C++Linux后台服务器开发高级架构师学习视频 点击 linux服务器学习资料 获取,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。免费学习链接:C/C++Linux服务器开发高级架构师/Linux后台架构师-学习视频 inet_listen接下来就是核心调用程序inet_listen了。
从这段代码中,第一个有意思的地方就是,listen这个系统调用可以重复调用!第二次调用的时候仅仅只能修改其backlog队列长度(虽然感觉没啥必要)。 首先,我们看下除fastopen之外的逻辑(fastopen以后开单章详细讨论)。也就是最后的inet_csk_listen_start调用。
这里最重要的一个调用sk->sk_prot->hash(sk),也就是inet_hash,其将当前sock链入全局的listen hash表,这样就可以在SYN包到来的时候寻找到对应的listen sock了。如下图所示: 如图中所示,如果开启了SO_REUSEPORT的话,可以让不同的Socket listen(监听)同一个端口,这样就能在内核进行创建连接的负载均衡。在Nginx 1.9.1版本开启了之后,其压测性能达到3倍! 半连接队列hash表和全连接队列在一开始翻阅的资料里面,都提到。tcp的连接队列有两个,一个是sync_queue,另一个accept_queue。但笔者仔细阅读了一下源码,其实并非如此。事实上,sync_queue其实是个hash表(syn_table)。另一个队列是icsk_accept_queue。 所以在本篇文章里面,将其称为reqsk_queue(request_socket_queue的简称)。 当然了,除了上面提到的qlen和sk_ack_backlog这两个计数器之外,还有一个qlen_young,其作用如下:
如下图所示: 至于SYN_ACK的重传定时器在内核中的代码为下面所示:
这个定时器在半连接队列不为空的情况下,以200ms(TCP_SYNQ_INTERVAL)为间隔运行一次。限于篇幅,就在这里不多讨论了。 为什么要存在半连接队列因为根据TCP协议的特点,会存在半连接这样的网络攻击存在,即不停的发SYN包,而从不回应SYN_ACK。如果发一个SYN包就让Kernel建立一个消耗极大的sock,那么很容易就内存耗尽。所以内核在三次握手成功之前,只分配一个占用内存极小的request_sock,以防止这种攻击的现象,再配合syn_cookie机制,尽量抵御这种半连接攻击的风险。 半连接hash表和全连接队列的限制由于全连接队列里面保存的是占用内存很大的普通sock,所以Kernel给其加了一个最大长度的限制。这个限制为:
如果超过这个somaxconn会被内核丢弃,如下图所示: 这种情况的连接丢弃会发生比较诡异的现象。在不设置tcp_abort_on_overflow的时候,client端无法感知,就会导致即在第一笔调用的时候才会知道对端连接丢弃了。 那么,怎么让client端在这种情况下感知呢,我们可以设置一下tcp_abort_on_overflow
设置后,如下图所示: 当然了,最直接的还是调大backlog!
backlog对半连接队列的影响这个backlog对半连接队列也有影响,如下代码所示:
我们在dmesg里面经常看到的
就是由于半连接队列满以后,Kernel发送cookie校验而导致。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 19:24:54- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |