手撕测试tcp服务器效率工具——以epoll和io_uring对比为例

服务器性能测试介绍

服务器的性能测试主要包括2部分:

  1. 并发量。能容纳多大的连接
  2. 效率。在不崩坏的情况下能对报文的处理效率。

本文主要进行效率测试,看看基于epoll模型和io_uring模型的tcp服务器,谁的效率更高。

测试思路

客户端(一个或多个)大量地向服务器发送报文,测试服务器的处理效率(tps:transaction per second,qps:queries per second)。这个或这些客户端也被成为测试工具。

测试工具需求

1、  基于tcp

2、  可以设置请求、线程与连接的数量。-n req -t threadnum -c connection。

在本文中,为了方便,我们为一个连接建立一个线程,也就是线程和连接一一对应。

getopt是一个解析命令行参数的函数,它不是一个线程安全的函数,尽量只在1个线程中使用,建议提前了解。

测试工具代码

代码有详细地注释,主要步骤为:

1、解析命令行参数,看看服务器的IP和port,以及要建立多少连接、发送多少数据等。

2、根据线程数建立线程,在线程里建立一个连接,连接服务器,并按每个线程的平均发送数据任务不间断地发送数据和接收数据。本案例中每笔报文的大小为64*8。

3、计算从开始发送到结束接收的耗时,并计算相关指标。

服务器的功能是:接收到什么数据就返回什么数据。

详细的服务器代码可看前文:

与epoll媲美的io_uring_io_uring tcp服务器-CSDN博客

用反应器模式和epoll构建百万并发服务器_如何设计一个支持百万并发的服务器-CSDN博客

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<unistd.h>#include<sys/time.h>
#include<pthread.h>
#include<arpa/inet.h>//设置该结构体用于存储线程函数所需的参数
typedef struct test_context_s{char serverip[16]; //服务器ipint port;	//服务器端口int threadnum;	//线程数量int connection;	//连接数量,此案例中与线程数量一致int requestion;	//请求数量,也就是报文数量int failed; //统计发送失败的次数,有个大概的数就行,所以没用原子变量
}test_context_t;typedef struct test_context_s test_context_t;//与服务器建立tcp连接,常规的socket然后connect
int connect_tcpserver(const char* ip,unsigned short port){int connfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in tcpserver_addr;memset(&tcpserver_addr,0,sizeof(struct sockaddr_in));tcpserver_addr.sin_family = AF_INET;tcpserver_addr.sin_addr.s_addr = inet_addr(ip);tcpserver_addr.sin_port = htons(port);int ret = connect(connfd,(struct sockaddr*)&tcpserver_addr,sizeof(struct sockaddr_in));if(ret){perror("connect");return -1;}return connfd;
}#define TIME_SUB_MS(tv1,tv2) ((tv1.tv_sec - tv2.tv_sec)*1000 + (tv1.tv_usec - tv2.tv_usec)/1000)//要发送给客户端的数据的基本单位
#define TEST_MESSAGE   "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz\r\n"#define RBUFFER_LENGTH 2048 //读数据的空间的大小,不一定用满
#define WBUFFER_LENGTH 2048 //写数据的空间的大小,不一定用满//客户端发送并接收数据
int send_recv_tcppkt(int fd){char wbuffer[WBUFFER_LENGTH] = {0};//设置每次发送的报文包含多少个基本单位int i = 0;for(i=0;i<8;i++){strcpy(wbuffer+i *strlen(TEST_MESSAGE),TEST_MESSAGE);}//发送报文int res = send(fd,wbuffer,strlen(wbuffer),0);if(res<0){exit(1);}//接收报文char rbuffer[RBUFFER_LENGTH] ={0};res = recv(fd,rbuffer,RBUFFER_LENGTH,0);if(res<=0){exit(1);}if(strcmp(rbuffer,wbuffer)!=0){return -1;}}//线程函数,主要作用是建立连接、发送接收报文
static void *test_qps_entry(void* arg){test_context_t *pctx = (test_context_t*)arg;//建立连接int connfd = connect_tcpserver(pctx->serverip,pctx->port);if(connfd<0){printf("connect_tcpserver failed!\n");return NULL;} //每个线程要发送的报文数量int count = pctx->requestion/pctx->threadnum;//发送报文int i=0;int res;while(i++<count){res = send_recv_tcppkt(connfd);if(res!=0){printf("send_recv_tcppkt failed\n");pctx->failed++;continue;}}return NULL;
}int main(int argc,char *argv[]){int ret =0;test_context_t ctx ={0};int opt;//getopt函数可以一次解析出带有名称的输入参数//注意这个函数是线程不安全的,while((opt = getopt(argc,argv,"s:p:t:c:n:?"))!=-1){switch(opt){case 's':printf("-s:%s\n",optarg);strcpy(ctx.serverip,optarg);//服务器IPbreak;		case 'p':printf("-p:%s\n",optarg);ctx.port = atoi(optarg);//服务器端口break;case 't':    printf("-t:%s\n",optarg);ctx.threadnum = atoi(optarg);//线程数break;case 'c':printf("-c:%s\n",optarg);ctx.connection = ctx.threadnum;//还是和线程数一致吧	break;case 'n':printf("-n:%s\n",optarg);ctx.requestion = atoi(optarg);break;default:return -1;					}}//线程数组pthread_t *ptid = malloc(ctx.threadnum *sizeof("pthread_t"));//开始大规模发送发送报文struct timeval tv_begin;	//记录报文开始发送的时间gettimeofday(&tv_begin,NULL);int i = 0;for(i=0;i<ctx.threadnum;i++){	//建立线程运行线程函数pthread_create(&ptid[i],NULL,test_qps_entry,&ctx);}for(i=0;i<ctx.threadnum;i++){pthread_join(ptid[i],NULL);}struct timeval tv_end;	//记录报文全部发送并接收完毕的时间gettimeofday(&tv_end,NULL);int time_used = TIME_SUB_MS(tv_end,tv_begin);//计算用时printf("success: %d, failed: %d, time_used: %d, qps: %d\n", ctx.requestion-ctx.failed, ctx.failed, time_used, ctx.requestion * 1000 / time_used);return 0;}

测试结果

epoll服务器

发送了100w数据,qps为33243

io_uring服务器

发送了100w数据,qps为43305

结论

在本机、本案例的情况下,io_uring服务器的效率比epoll服务器的效率高约30%。

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

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

相关文章

3D 建模中的法线贴图解释

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 什么是 3D 建模中的法线贴图 3D 对象由多边形组成&#xff1a;平面、…

Java的maven

一.概念&#xff1a; 是一款用于管理和构建java项目的工具 作用: 方便项目的依赖管理 统一项目的结构,方便程序员开发及维护 提供了一套标准的项目构建流程,方便编译和构建 二.仓库类型: 本地仓库>自己计算机上的一个目录 中央仓库>由Maven团队维护的全球唯一的。…

C语言之进制转换

C语言之进制转换 一、引言二、十进制与二进制、八进制、十六进制三、二进制与八进制、十六进制四、八进制与十六进制 一、引言 在C语言中&#xff0c;经常使用的整数的进制有十进制、二进制、十六进制&#xff08;在C语言中以0x或0X为前缀&#xff09;、八进制&#xff08;在C…

圆中点算法

中心在原点&#xff0c;半径为 R 的圆的隐式函数方程为 F ( x , y ) x 2 y 2 − R 2 0 F(x, y) x^2 y^2 - R^2 0 F(x,y)x2y2−R20 把像素上的点的坐标代入上述隐式方程 八分法画圆算法 利用坐标轴和与坐标轴夹角 45 度的直线 原理 假设圆弧起点 x 0 x0 x0&#xff0…

labuladong日常刷题-双指针 | LeetCode 83删除排序链表中的重复元素 5最长回文子串

双指针操作链表与字符串 LeetCode 83 删除排序链表中的重复元素 2023.12.28 题目链接labuladong讲解[链接] ListNode* deleteDuplicates(ListNode* head) {/*暴力求解ListNode* cur new ListNode();ListNode* prenode cur;cur->next head;cur cur->next;while(cu…

实习知识整理12:点击购物车渲染出购物车中的商品并实现在购物车界面对商品价格和数量的相关操作

1. 点击购物车渲染出购物车商品界面 通过userId从购物车表中查找商品的相关信息 前端&#xff1a;需要向后端传递userId 后端&#xff1a; CartMapper.java CartMapper.xml CartService.java 接口 CartServiceImpl.java 实现类 CartController.java cartIndex.html页面 …

使用自带密钥 (BYOK) 的Azure信息保护云退出

上篇我们讲了使用Microsoft托管密钥的Azure信息保护云退出&#xff0c;本文我们将介绍使用自带密钥 (BYOK) 的Azure信息保护云退出。 自带密钥 (BYOK) 由客户在 nCipher HSM 中创建&#xff0c;并安全地传输到基于 HSM 的 Azure Key Vault&#xff0c;供 AIP 使用。 由于 Micro…

【产品评测】戴尔G15 5510笔记本电脑拆机实拍

笔者最近入手了一台戴尔G15 5510笔记本电脑&#xff0c;第一时间将其初步拆解&#xff0c;了解其内部设计、构造和扩展性。 一、机身总览 1、屏幕和键盘 2、A面 略粗糙的手感。 3、D面 D面共有8颗螺丝&#xff0c;其中4颗&#xff08;上有保护膜&#xff09;为戴尔家比较常见…

创建型设计模式 - 抽象工厂模式 - JAVA

创建型设计模式 - 抽象工厂设计模式 一. 简介二. 列子2.1 定义电脑的抽象类和子类2.2 定义抽象工厂类和其实现类2.3 测试 三. 抽象工厂设计模式的好处四. 抽象工厂模式的案例 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续…

实时交通标志检测和分类(代码)

交通标志检测和分类技术是一种基于计算机视觉和深度学习的先进技术&#xff0c;能够识别道路上的各种交通标志&#xff0c;并对其进行分类和识别。这项技术在智能交通系统、自动驾驶汽车和交通安全管理领域具有重要的应用前景。下面我将结合实时交通标志检测和分类的重要性、技…

Java技术栈 —— Redis的雪崩、穿透与击穿

Java技术栈 —— Redis的雪崩、穿透与击穿 〇、实验的先导条件&#xff08;NginxJmeter&#xff09;一、Redis缓存雪崩、缓存穿透、缓存击穿1.1 雪崩1.2 穿透1.3 击穿 二、Redis应用场景——高并发2.1 单机部署的高并发问题与解决&#xff08;JVM级别锁&#xff09;2.2 集群部署…

简述Redis备份策略以及对应的实现机制

引言 Redis作为高性能的内存数据库&#xff0c;数据的安全性至关重要。一旦数据丢失&#xff0c;可能会对业务造成重大影响。因此&#xff0c;备份Redis数据是每个Redis使用者都必须考虑的问题。本文将介绍Redis的备份策略以及对应的实现机制。 一、备份策略 1.1 定期备份 …