Linux多线程服务端编程:使用muduo C++网络库 学习笔记 附录D 关于TCP并发连接的几个思考题与试验

news2024/9/25 13:14:21

前几天作者在新浪微博上出了两道有关TCP的思考题,引发了一场讨论(http://weibo.com/1701018393/eCuxDrtaONn)。

第一道初级题目是:有一台机器,它有一个IP,上面运行了一个TCP服务程序,程序只侦听一个端口,问:从理论上讲(只考虑TCP/IP这一层面,不考虑IPv6)这个服务程序可以支持多少并发TCP连接?(答65536上下的直接出局)

具体来说,这个问题等价于:有一个TCP服务程序的地址是1.2.3.4:8765,问它从理论上能接受多少个并发连接?

第二道进阶题目是:一台被测机器A,功能同上,同一交换机上还接有一台机器B,如果允许B的程序直接收发以太网frame,问:让A承担10万个并发TCP连接需要用多少B的资源?100万个呢?

从讨论的结果看,很多人做出了第一道题,而第二道题则几乎无人问津。这里先不公布答案(第一题答案见文末),让我们继续思考一个本质的问题:一个TCP连接要占用多少系统资源?

在现在的Linux操作系统上,如果用socket(2)或accept(2)来创建TCP链接,那么每个连接至少要占用一个文件描述符(file descriptor)。为什么说“至少”?因为文件描述符可以复制,比如dup();也可以被继承,比如fork();这样可能出现系统中同一个TCP连接有多个文件描述符与之对应。据此,很多人给出的第一题答案是:并发连接数受限于系统能同时打开的文件数目的最大值。这个答案在实践中是正确的,却不符合原题意。

如果抛开操作系统层面,只考虑TCP/IP层面,建立一个TCP连接有哪些开销?理论上最小的开销是多少?考虑两个场景:
1.假设有一个TCP服务程序,向这个程序成功发起连接需要做哪些事情?换句话说,如何才能让这个TCP服务程序认为有客户连接到了它(让它的accept(2)调用正常返回)?

2.假设有一个TCP客户端程序,让这个程序成功建立到服务器的连接需要做哪些事情?换句话说,如何才能让这个TCP客户端程序认为它自己已经连接到服务器了(让它的connect(2)调用正常返回)?

以上这两个问题问的不是如何编程,如何调用Sockets API,而是问如何让操作系统的TCP/IP协议栈认为任务已经成功完成,连接已经成功建立。

学过TCP/IP协议,理解三路握手的读者想必明白,TCP连接是虚拟的连接,不是电路连接。维持TCP连接理论上不占用网络资源(会占用两头程序的系统资源)。只要连接的双方认为TCP连接存在,并且可以互相发送IP packet,那么TCP连接就一直存在。

对于问题1,向一个TCP服务程序发起一个连接,客户端(为明白起见,以下称为faketcp客户端)只需要做三件事情(三路握手):
1a.向TCP服务程序发一个IP packet,包含SYN的TCP segment;

1b.等待对方返回一个包含SYN和ACK的TCPsegment;

1c.向对方发送一个包含ACK的segment。

faketcp客户端在做完这三件事情之后,TCP服务器程序会认为连接已建立。而做这三件事情并不占用客户端的资源,如果faketcp客户端程序可以绕开操作系统的TCP/IP协议栈,自己直接发送并接收IP packet或Ethernet frame的话。换句话说,faketcp客户端可以一直重复做这三件事情,每次用一个不同的IP:PORT,在服务端创建不计其数的TCP连接,而faketcp客户端自己毫发无损。我们很快将看到如何用程序来实现这一点。

对于问题2,为了让一个TCP客户端程序认为连接已建立,faketcp服务端也只需要做三件事情:
2a.等待客户端发来的SYN TCP segment;

2b.发送一个包含SYN和ACK的TCP segment;

2c.忽视对方发来的包含ACK的segment。

faketcp服务端在做完头两件事情(收一个SYN、发一个SYN+ACK)之后,TCP客户端程序会认为连接已建立。而做这三件事情并不占用faketcp服务端的资源。换句话说,faketcp服务端可以一直重复做这三件事,接受不计其数的TCP连接,而faketcp服务端自己毫发无损。我们很快将看到如何用程序来实现这一点。

基于对以上两个问题的分析,说明单独谈论“TCP并发连接数”是没有意义的,因为连接数基本上是要多少有多少。更有意义的性能指标或许是:“每秒收发多少条消息”、“每秒收发多少字节的数据”、“支持多少个活动的并发客户”等等。

faketcp的程序实现

为了验证上面的说法,作者写了几个小程序来实现faketcp,这几个程序可以发起或接受不计其数的TCP并发连接,并且不消耗操作系统资源,连动态内存分配都不会用到。代码见recipes/faketcp,可以直接用make编译。

作者家里有一台运行Ubuntu Linux 10.04的PC,hostname是atom,所有的试验都在这上面进行。家里试验环境的网络配置如图D-1所示。
在这里插入图片描述
作者在附录A中曾提到过“可以用TUN/TAP设备在用户态实现一个能与本机点对点通信的TCP/IP协议栈”,这次的试验正好可以用上这个办法。试验的网络配置如图D-2所示。
在这里插入图片描述
具体做法是:在atom上通过打开/dev/net/tun设备来创建一个tun0虚拟网卡,然后把这个网卡的地址设为192.168.0.1/24,这样faketcp程序就扮演了192.168.0.0/24这个网段上的所有机器。atom发给192.168.0.2~192.168.0.254的IP packet都会发给faketcp程序,faketcp程序可以模拟其中任何一个IP给atom发IP packet。

程序分成几步来实现。

第一步:实现ICMP echo协议,这样就能ping通faketcp了。代码见recipes/faketcp/icmpecho.cc。

其中响应ICMP echo request的函数是icmp_input(),位于recipes/faketcp/faketcp.cc。这个函数在后面的程序中也会用到。

运行方法,打开3个命令行窗口:
1.在第1个窗口运行sudo ./icmpecho,程序显示
在这里插入图片描述
2.在第2个窗口运行
在这里插入图片描述
3.在第3个窗口运行:
在这里插入图片描述
注意到每个192.168.0.X的IP都能ping通。

第二步:实现拒绝TCP连接的功能,即在收到SYN TCP segment的时候发送RST segment。代码见recipes/faketcp/rejectall.cc。

运行方法,打开3个命令行窗口,头两个窗口的操作与前面相同,运行的faketcp程序是./rejectall。在第3个窗口运行
在这里插入图片描述
注意到向其中任意一个IP发起的TCP连接都被拒绝了。

第三步:实现接受TCP连接的功能,即在收到SYN TCP segment的时候发回SYN+ACK。这个程序同时处理了连接断开的情况,即在收到FIN segment的时候发回FIN+ACK。代码见recipes/faketcp/acceptall.cc。

运行方法,打开3个命令行窗口,步骤与前面相同,运行的faketcp程序是./acceptall。这次会发现nc能和192.168.0.X中的每一个IP每一个port都能联通。还可以在第4个窗口中运行netstat -tpn,以确认连接确实建立起来了。如果在nc中输入数据,数据会堆积在操作系统中,表现为netstat显示的发送队列(Send-Q)的长度增加。

第四步:在第三步接受TCP连接的基础上,实现接收数据,即在收到包含payload数据的TCP sengment时发回ACK。代码见recipes/faketcp/discardall.cc。

运行方法,打开3个命令行窗口,步骤与前面相同,运行的faketcp程序是discardall。这次会发现nc能和192.168.0.X中的每一个IP每一个port都能连通,数据也能发出去。还可以在第4个窗口中运行netstat -tpn,以确认连接确实建立起来了,并且发送队列的长度为0。

这一步已经解决了前面的问题2,扮演任意TCP服务端。

第五步:解决前面的问题1,扮演客户端向atom发起任意多的连接。代码见recipes/faketcp/connectmany.cc。

这一步的运行方法与前面不同,打开4个命令行窗口:
1.在第1个窗口运行sudo ./connectmany 192.168.0.1 2007 1000,表示将向192.168.0.1:2007发起1000个并发连接。程序显示
在这里插入图片描述
2.在第2个窗口运行
在这里插入图片描述
3.在第3个窗口运行一个能接收并发TCP连接的服务程序,可以是httpd,也可以是muduo的echo或discard示例,程序应listen 2007端口。

4.在第1个窗口中按回车键,再在第4个窗口中用netstat -tpn命令来观察并发连接。

有兴趣的话,还可以继续扩展,做更多的有关TCP的试验,以进一步加深理解,验证操作系统的TCP/IP协议栈面对不同输入的行为。甚至可以按作者在附录A中提议的那样,实现完整的TCP状态机,做出一个简单地mini tcp stack。

第一道题的答案:

在只考虑IPv4的情况下,并发输的理论上限是2 48 ^{48} 48。考虑某些IP段被保留了,这个上界可适当缩小,但数量级不变。实际的限制是操作系统全局文件描述符的数量,以及内存大小。

一个TCP连接有两个end points,每个end point是{ip, port},题目说其中一个end point已经固定,那么留下一个end point的自由度,即2 48 ^{48} 48。客户端IP的上限是2 32 ^{32} 32个,每个客户端IP发起连接的上限是2 16 ^{16} 16,乘到一起得到理论上限。

即便客户端使用NAT,也不影响这个理论上限。

在真实的Linux系统中,可以通过调整内核参数来支持上百万并发连接,具体做法见:
1.http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-3。

2.http://www.erlang-factory.com/upload/presentations/558/efsf2012-whatsapp-scaling.pdf。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32学习7 按键扫描

STM32学习7 按键扫描 一、实验电路介绍二、按键GPIO初始化三、扫描原理1. GPIO引脚配置2. 状态轮询3. 按键状态检测4. 循环扫描的优缺点优点:缺点: 四、一次扫描与持续扫描五、代码实现1. 头文件定义2. 函数实现3. 主体函数 一、实验电路介绍 本实验使用…

代码随想录算法训练营第七天

● 自己看到题目的第一想法 第454题.四数相加II 方法&#xff1a; 方法一&#xff1a; 暴力法 思路&#xff1a; 注意&#xff1a; 代码&#xff1a; class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<i…

ABB眼中AI推动机器人创新的三大方向

文 | BFT机器人 ABB的历史是一部充满革新与进步的史诗&#xff0c;它的机器人篇章始于1974年&#xff0c;那一年它向世界推出了被誉为“全球首个商用全电动机器人”的IRB 6。时隔半个世纪&#xff0c;ABB的机器人产品线已变得无比强大和多元&#xff0c;囊括了先进的工业机械臂…

OpenAI 与开源多语言嵌入模型

原文地址&#xff1a;OpenAI vs Open-Source Multilingual Embedding Models 选择最适合您的数据的模型 2024 年 2 月 25 日 OpenAI最近发布了他们的新一代embedding模型&#xff0c;称为embeddingv3&#xff0c;他们描述是他们性能最好的embedding模型&#xff0c;具有更高…

MySQL8安装切换密码验证方式

一、MySQL8中新增了一种密码验证方式&#xff1a;caching_sha2_password&#xff0c;如果安装时选择了如下方式&#xff1a; 则数据库使用新的caching_sha2_password密码验证方式。 二、如果安装时选择了caching_sha2_password验证方式&#xff0c;而安装后想发回传统的mysql_…

云原生之容器编排实践-ruoyi-cloud项目部署到K8S:Redis7.2.3

背景 前面搭建好了 Kubernetes 集群与私有镜像仓库&#xff0c;终于要进入服务编排的实践环节了。本系列拿 ruoyi-cloud 项目进行练手&#xff0c;按照 MySQL &#xff0c; Nacos &#xff0c; Redis &#xff0c; Nginx &#xff0c; Gateway &#xff0c; Auth &#xff0c;…

Power BI vs Superset BI 调研报告

调研结论 SupersetPower BI价格开源①. Power BI Pro 每人 $10/月($120/年/人) ②. Power BI Premium 每人 $20/月($240/年/人) ③. Power BI Embedded:4C10G $11W/年 权限基于角色的访问控制,支持细粒度的访问: 表级别、库级别、图表级别,看板级别,用户级别 基于角色…

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行功能&#xff0c;即滚动 UI 显示当前源代码范围。便于在代码行数比较多的时候更好的知道自己所在的位置。粘性滚动UI 显示用户在滚动期间所处的范围&#xff0c;将显示编辑器顶部所在的类/接口/命名空间/函数/方法/构造函数&a…

JavaScript之引用类型

系列文章目录 文章目录 系列文章目录前言一、Object类型二、Array类型三、Date类型四、Function类型五、内置对象 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文…

C++ opencv 学习

文章目录 1、创建窗口2、读取图片3、视频采集4、Mat的使用5、异或操作6、通道分离&#xff0c;通道合并7、色彩空间转换8、最大值、最小值9、绘制图像10、多边形绘制11、随机数12、鼠标实时绘制矩形13、归一化14、resize操作15、旋转翻转16、视频操作17、模糊操作18、高斯模糊操…

ONLYOFFICE文档8.0全新发布:私有部署、卓越安全的协同办公解决方案

ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案 文章目录 ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案摘要&#x1f4d1;引言 &#x1f31f;正文&#x1f4da;一、ONLYOFFICE文档概述 &#x1f4ca;二、ONLYOFFI…

字符串之manacher(马拉车)算法

这个算法用途就是查找字符串内的最长回文串 正常情况下&#xff0c;我们查找回文序列&#xff0c;会去用双指针比较&#xff0c;这样的话数据大的时候&#xff0c;时间复杂度就上去了&#xff0c;其实这个马拉车算法和kmp算法的一部分是有些相像的&#xff0c;建议先看我的上篇…

00X集——acdbpolyline与acdb2dpolyline区别

下图中选择的线为通过ThisDrawing.ModelSpace.AddPolyline(points)创建的&#xff0c;包含2个点 通过代码查询objectname,如下图acdb2dpolyline ObjectARX 中提供了三种多段线的相关类:AcDbPolyline 、AcDb2dPolyline 和 AcDb3dPolyline 。其中&#xff0c;利用AutoCAD 的内部…

【Java项目介绍和界面搭建】拼图小游戏——打乱图片顺序

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

现代化数据架构升级:毫末智行自动驾驶如何应对年增20PB的数据规模挑战?-OceanBase案例

毫末智行是一家致力于自动驾驶的人工智能技术公司&#xff0c;其前身是长城汽车智能驾驶前瞻分部&#xff0c;以零事故、零拥堵、自由出行和高效物流为目标&#xff0c;助力合作伙伴重塑和全面升级整个社会的出行及物流方式。 在自动驾驶领域中&#xff0c;是什么原因让毫末智行…

力扣601 体育馆的人流量

在解决"连续三天及以上人流量超过100的记录"问题时&#xff0c;MySQL方案作为力扣解决问题的方案通过窗口函数和分组技巧高效地识别连续记录。而Python与Pandas方案作为扩展则展示了在数据处理和分析方面的灵活性&#xff0c;通过行号变换和分组计数来筛选符合条件的…

unity学习(46)——服务器三次注册限制以及数据库化角色信息1--数据流程

1.先找到服务器创建角色信息代码的位置&#xff0c;UserBizImpl.cs中&#xff1a; public PlayerModel create(string accId, string name, int job) {PlayerModel[] playerModelArray this.list(accId);//list是个自建函数&#xff0c;本质通过accId来查询if (playerModelAr…

【机器人最短路径规划问题(栅格地图)】基于模拟退火算法求解

代码获取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主获取 基于模拟退火算法求解机器人最短路径规划问题&#xff08;栅格地图&#xff09;的仿真结果 仿真结果&#xff1a; 初始解的路径规划图 收敛曲线&#xff1a; 模拟退火算法求解的路径规划图 结论&#xff…

笨办法学 Python3 第五版(预览)(一)

原文&#xff1a;Learn Python the Hard Way, 5th Edition (Early Release) 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 模块 1&#xff1a;Python 入门 练习 0&#xff1a;准备工作 这个练习没有代码。这只是你完成的练习&#xff0c;让你的计算机运行 Python。…

视频编码面试基础题

视频基础知识&#xff1a; RGB彩色原理&#xff1a; RGB是指光学三原色红、绿和蓝&#xff0c;通过这3种的数值&#xff08;0-255&#xff09;改变可以组成其他颜色&#xff0c;全0时为黑色&#xff0c;全255时为白色。RGB是一种依赖于设备的颜色空间&#xff1a;不同设备对特定…