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

前几天作者在新浪微博上出了两道有关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.mzph.cn/news/717133.shtml

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

相关文章

StarRocks实战——松果出行实时数仓实践

目录 一、背景 二、松果出行实时OLAP的演进 2.1 实时数仓1.0的架构 2.2 实时数仓2.0的架构 2.3 实时数仓3.0的架构 三、StarRocks 的引入 四、StarRocks在松果出行的应用 4.1 在订单业务中的应用 4.2 在车辆方向的应用 4.3 StarRocks “极速统一” 落地 4.4 StarRoc…

Lambda、Function、StreamAPI详解

目录 1、Lambda 2、Function 3、StreamAPI 中间操作:Intermediate Operations 终止操作:Terminal Operation 1、Lambda Java8语法糖:参数列表 箭头 方法体 package com.atguiggu.lambda;import java.util.*; import java.util.funct…

分布式ID生成系统之雪花算法详解

在当今的云计算和微服务架构盛行的时代,分布式系统已成为软件开发的重要组成部分。随着系统规模的扩大和业务的复杂化,对数据一致性和唯一性的要求也越来越高,尤其是在全局唯一标识符(ID)的生成上。因此,分…

代码随想录算法训练营Day48 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机 II

121.买卖股票的最佳时机 &#xff08;想写动态规划写着写着变成贪心了&#xff09; 半贪心半动规&#xff1a; int maxProfit(vector<int>& prices) {vector<int> dp(prices.size(), 0);int minVal prices[0];for (int i 1; i < prices.size(); i) {//…

yolov5训练太慢的解决方案

问题原因 训练太慢大多是因为没有安装CUDA和pytorch&#xff0c;导致的只有cpu在跑&#xff0c;显卡没跑 这就是很典型的。 解决方案 第一步&#xff1a;安装CUDA 在本机上面安装CUDA,记住只有N卡可以安装&#xff0c;一开始的电脑是自带CUDA的。 如果不是自带的CUDA&…

Apache Paimon Flink引擎解析

Paimon 支持 Flink 1.17, 1.16, 1.15 和 1.14&#xff0c;当前 Paimon 提供了两类 Jar 包&#xff0c;一类支持数据读写&#xff0c;另一类支持其它操作&#xff08;compaction&#xff09; Version Type Jar Flink 1.18 Bundled Jar paimon-flink-1.18-0.7…

SentenceTransformer简单使用

SentenceTransformer简单使用 1 SentenceTransformer介绍 SentenceTransformer主要用于对句子、文本和图像进行嵌入。可用于文本和图像的相似度对比查找等 # SentenceTransformer官网地址 https://www.sbert.net/# 安装SentenceTransformer pip install -U sentence-transfo…

求数字的每一位之和

求数字的每一位之和 题目描述&#xff1a;解法思路&#xff1a;解法代码&#xff1a;运行结果&#xff1a; 题目描述&#xff1a; 输入一个整数m&#xff0c;求这个整数m的每⼀位之和&#xff0c;并打印。 测试1&#xff1a; 输⼊&#xff1a;1234 输出&#xff1a;10 测试2&…

土壤侵蚀量化评估

根据之前的文章,已经算出了R、K、LS、C、P 现在计算土壤侵蚀,将几个前期制作好的因子的TIFF文件,用栅格计算器相乘 发现局部地区存在轻度侵蚀,大部分区域是微度侵蚀 然后对比了一下范围 其中的几个因子都在文献范围内,说明计算结果并未出错,可能就是研究区正常范围和结…

6020一拖二快充线:手机充电的革命性创新

在快节奏的现代生活中&#xff0c;手机已不仅仅是一个通讯工具&#xff0c;更是我们工作、学习和娱乐的得力助手。然而&#xff0c;手机的电量问题一直是困扰着我们的难题。为了解决这个问题&#xff0c;市场上出现了一种名为“一拖二快充线”的充电设备&#xff0c;它不仅具备…

etcd入门-(1)安装篇

一、etcd安装 https://github.com/etcd-io/etcd/releases 根据需要下载安装etcd, 确保添加到环境变量 执行 etcd -v 查看安装版本 二、etcd运行 本地运行集群 1.首先安装goreman go install github.com/mattn/goremanlatest2.准备Procfile 将脚本下载到本地&#xff0c;或者复…

八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX

目录 前言0. 简述1. camera.backbone.onnx(fp16)2. camera.backbone.onnx(int8)3. camera.vtransform.onnx(fp16)4. fuser.onnx(fp16)5. fuser.onnx(int8)6. lidar.backbone.xyz.onnx7. head.bbox.onnx(fp16)总结下载链接参考 前言 自动驾驶之心推出的《CUDA与TensorRT部署实战…

每日一类:Qt中的万能容器

在Qt框架中&#xff0c;QVariant类扮演着一个非常重要的角色。它是一个万能容器类&#xff0c;可以存储Qt中的任何基本类型数据&#xff0c;包括自定义类型。这种灵活性使得QVariant成为Qt编程中不可或缺的工具&#xff0c;特别是在需要处理不同类型数据或进行对象间通信时。 …

Unity UGUI之Scrollbar基本了解

Unity的Scrollbar组件是用于在UI中创建滚动条的组件之一。滚动条通常与其他可滚动的UI元素&#xff08;如滚动视图或列表&#xff09;一起使用&#xff0c;以便用户可以在内容超出可见区域时滚动内容。 以下是Scrollbar的基本信息和用法: 1、创建 在Unity的Hierarchy视图中右…

柯西矩阵介绍

经典定义 柯西矩阵&#xff08;Cauchy Matrix&#xff09;&#xff0c;是一种特殊类型的矩阵&#xff0c;它在数学中的多个领域&#xff0c;包括线性代数、数值分析和插值理论中都有重要应用。柯西矩阵以19世纪法国数学家奥古斯丁-路易柯西的名字命名。 柯西矩阵是一个方阵&am…

Krylov matrix

Krylov矩阵是一种在数值线性代数中使用的矩阵&#xff0c;尤其是在迭代解法中用于求解线性方程组、特征值问题和其他线性代数问题。它是由俄国数学家阿列克谢尼古拉耶维奇克雷洛夫&#xff08;Alexei Nikolaevich Krylov&#xff09;的名字命名的。 Krylov子空间由以下形式的矩…

jetson nano——编译安装opencv==4.4

目录 1.下载源码&#xff0c;我提供的链接如下&#xff1a;1.1文件上传的路径位置&#xff0c;注意ymck是我自己的用户名&#xff08;你们自己换成你们自己相对应的就行&#xff09; 2.解压文件3.安装依赖4.增加swap交换内存4.1临时增加交换内存swap4.2永久增加swap 5.安装open…

2024-03-03 作业

作业要求&#xff1a; 1.使用fwrite、fread将一张随意的bmp图片&#xff0c;修改成德国的国旗 2.使用提供的getch函数&#xff0c;编写一个专门用来输入密码的函数&#xff0c;要求输入密码的时候&#xff0c;显示 * 号&#xff0c;输入回车的时候&#xff0c;密码输入结束 作业…

学习Android的第十九天

目录 Android ExpandableListView 分组列表 ExpandableListView 属性 ExpandableListView 事件 ExpandableListView 的 Adapter 范例 参考文档 Android ViewFlipper 翻转视图 ViewFlipper 属性 ViewFlipper 方法 为 ViewFlipper 加入 View 例子&#xff1a;全屏幕可…

【MySQL】索引(重点)-- 详解

一、索引 没有索引&#xff0c;可能会有什么问题&#xff1f; 索引 &#xff1a;提高数据库的性能&#xff0c;索引是物美价廉的东西了。不用加内存&#xff0c;不用改程序&#xff0c;不用调 sql &#xff0c;只要执行正确的 create index &#xff0c;查询速度就可能提高成…