epoll实现同时承载100w客户端的数量

news2024/11/29 12:49:03

概念

先表明,这里是让epoll能够同时承受100w的连接,不针对业务处理。

对于百万并发的业务处理,其前提条件就是要同时承受住100w的连接。

程序源码

  epoll的源码直接给出来

/*
    支持百万并发的 reactor
    1.其主要限制在于Linux系统的限制,需要修改一些参数

    测试: 3个标准
    1.wrk       --> qps 一秒钟能处理的请求量
    2.并发连接量 --> 
    3.iperf     --> 测试带宽(硬件能力)

    // gcc reactor.c -oreactor -mcmodel=medium -g
*/

#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

#define PORT 2480
#define MAX_EVENTS 1024

#define MAX_BUFFER_SIZE 1024

// 事件结构 -- 封装 读写缓冲区,读写事件处理方法
typedef int (*RCALLBACK)(int fd);

typedef struct _CONN_ITEM_{

    int fd;
    int rLen;
    int wLen;
    char readBuffer[MAX_BUFFER_SIZE];
    char writeBuffer[MAX_BUFFER_SIZE];

    // 函数指针 -- 这里我们根据 epoll返回的特性分为读事件和写事件
    RCALLBACK send_cb;
    RCALLBACK recv_cb;

}CONN_ITEM, LPTIEM;

CONN_ITEM connLists[1048576] = {0};
int epfd;

// 读事件
int send_cb(int fd){

    int Len = connLists[fd].wLen;
    int count = send(fd, connLists[fd].readBuffer, Len, 0);


    struct epoll_event evnet;
    evnet.data.fd = fd;
    evnet.events = EPOLLIN;
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &evnet);

}

// 写事件
int recv_cb(int fd){

    char *buffer = connLists[fd].readBuffer;
    int rLen = connLists[fd].rLen;

    int count = recv(fd, buffer + rLen, MAX_BUFFER_SIZE - rLen, 0);
    if(0 == count){
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
        close(fd);
    }
    else
    {
        connLists[fd].rLen += count;

        // 回写数据
        memcpy(connLists[fd].writeBuffer, connLists[fd].readBuffer, connLists[fd].rLen);
        connLists[fd].rLen -= 0;
        connLists[fd].wLen = connLists[fd].rLen;

        // 将事件修改为触发写事件
        struct epoll_event event;
        event.data.fd = fd;
        event.events = EPOLLOUT;               
        epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
    }
}


// 连接事件 - 属于读事件
int accept_cb(int fd){

    int ret = 0;

    struct sockaddr_in clienAddr;
    socklen_t len = sizeof(clienAddr);
    int connfd = accept(fd, (struct sockaddr*)&clienAddr, &len);
    if(connfd){
        // 将新的 fd加入到epoll中
        struct epoll_event event;
        event.data.fd = connfd;
        event.events = EPOLLIN;
        connLists[connfd].send_cb = send_cb;
        connLists[connfd].recv_cb = recv_cb;

        connLists[connfd].rLen = 0;
        connLists[connfd].wLen = 0;
        memset(connLists[connfd].readBuffer, 0, MAX_BUFFER_SIZE);
        memset(connLists[connfd].writeBuffer, 0, MAX_BUFFER_SIZE);

        ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);
        if(-1 == ret){
            perror("epoll_ctl");
        }
    }

}

int main(){

    int ret = 0;
    int i = 0;

    // TCP
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd){
        perror("socket");
        return -1;
    }

    // addr
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(PORT);

    ret = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in));
    if(-1 == ret){
        perror("bind");
        return -1;
    }

    // 这个地方的第二个参数,表示未连接的个数能容纳几个,防止syn泛洪
    listen(sockfd, 10);

    // 建立 epoll,参数以无意义(内核>=2.6.8) > 0
    epfd =  epoll_create(10);
    if(-1 == ret){
        perror("epoll_create");
        return -1;
    }

    // 将sockfd加入到 epoll中
    struct epoll_event event;
    event.data.fd = sockfd;
    event.events = EPOLLIN;           // 指定监控的事件
    connLists[sockfd].fd = sockfd;
    //connLists[sockfd].accept_cb = accept_cb;
    connLists[sockfd].recv_cb = accept_cb;
    connLists[sockfd].send_cb = send_cb;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
    if(-1 == ret){
        perror("epoll_ctl");
        return -1;
    }

    // 不断的监视消息 - 可能会触发多次
    struct epoll_event events[MAX_EVENTS];
    while(1){

        int ready = epoll_wait(epfd, events, MAX_EVENTS, -1);
        if(-1 == ret){
            perror("epoll_wait");
            return -1;
        }

        for(i = 0; i < ready; ++i){
            
            int fd = events[i].data.fd;
            if(events[i].events & EPOLLIN){
                // 读事件
                ret = connLists[fd].recv_cb(fd);
            }
            else if(events[i].events & EPOLLOUT){
                // 写事件
                ret = connLists[fd].send_cb(fd);
            }
        }
    }
    
    close(epfd);
    close(sockfd);

    return 0;
}



测试收发数据:

 测试程序

        逻辑,这里我们没有那么多IP进行测试,只能不断的建立连接,断开连接。在实际的应用过程中也是这样的,在后续的工作中,需要测试并发量的情况下,一下代码程序依旧适用。

        

正片开始

多试几次,发现每次都在一千左右崩溃掉了。

为什么会出现这种情况?

        其实不难理解,我们能够知道一个socket会对于一个fd(伪文件),对于一个进程而言,能够建立的连接数量是有限的,我们可以进行修改。

ulimit -n 1048576(一百万) --> 1024 *1024

修改完测试:

这里的情况是,在Linux中默认允许分配端口大概是2万多,我们改下配置文件。

客户端需要做更改,客户端的端口是随机分配的,到两万左右就嗝屁了。(这个根据内核版本决定)。

增加一行:

fs.file-max = 1048576 一个进程能打开的最哒的文件描述符的大小

server端直接崩了,出现这种情况大概率是内存不足的问题。换句话说,当协议盏暂用内存的比例到达一定比例的时候,进程会被操作系统强制终止。我们需要调整配置...

sudo modprobe ip_conntrack

调整完再测试下:

现在能跑到五十多万,显示连接被拒绝,说明服务端断掉了,我们继续调整配置。

接下来就是不断的调整这些数值...实在跑不上去,有可能是网络问题或者虚拟机内存问题,直接把虚拟机内存再加大。

再调整...mmp今天一定把他弄上去

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

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

相关文章

小白教学!几个步骤入门AI动画视频制作

公众号&#xff1a;算法一只狗 文章目录 文本视频生成软件&#xff1a;PIKA小黑子表情包熊猫头表情包 动画视频制作故事和分镜文本制作动画生成与拼接 总结 要介绍动画生成之前&#xff0c;先让大家来看看我生成的动画视频&#xff1a; AI动画生成故事 上面的视频我只用了不到2…

Android12 WIFI 无法提供互联网连接

平台 RK3588 Android 12 问题描述 ConnectivityService是Android系统中负责处理网络连接的服务之一。它负责管理设备的网络连接状态&#xff0c;包括Wi-Fi、移动数据、蓝牙等。 在Android系统中&#xff0c;ConnectivityService提供了一些关键功能&#xff0c;包括但不限于…

Docker部署开源分布式任务调度平台DolphinScheduler并实现远程访问办公

文章目录 前言1. 安装部署DolphinScheduler1.1 启动服务 2. 登录DolphinScheduler界面3. 安装内网穿透工具4. 配置Dolphin Scheduler公网地址5. 固定DolphinScheduler公网地址 前言 本篇教程和大家分享一下DolphinScheduler的安装部署及如何实现公网远程访问&#xff0c;结合内…

【Java期末复习资料】(2)常见例题 //持续更新

本文章主要是常见例题&#xff0c;解析不会太详细&#xff0c;有问题、不会的可以给我发消息哦&#xff0c;后续会出模拟卷 常见例题&#xff1a; 1.下列跟Java技术平台有关的是&#xff08;ABD&#xff09; A.JVM B.JDK C.JPN D.JRE 2.面向对象的特征包括&#xff08;ACD&…

uniapp实战 —— 可滚动区域 scroll-view (自适配高度,下拉刷新)

自适配高度 自定义的顶部导航栏&#xff0c;可参考博文 https://blog.csdn.net/weixin_41192489/article/details/134852124 如图可见&#xff0c;在页面滚动过程中&#xff0c;顶部导航栏和底栏未动&#xff0c;仅中间的内容区域可滚动。 整个页面的高度设置为 100%&#xf…

【SQL开发实战技巧】系列(四十九):Oracle12C常用新特性☞表分区部分索引(Partial Indexes)

系列文章目录 【SQL开发实战技巧】系列&#xff08;一&#xff09;:关于SQL不得不说的那些事 【SQL开发实战技巧】系列&#xff08;二&#xff09;&#xff1a;简单单表查询 【SQL开发实战技巧】系列&#xff08;三&#xff09;&#xff1a;SQL排序的那些事 【SQL开发实战技巧…

漏洞复现-用友NC任意文件上传漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

架构LNMP

目录 1.安装Nginx服务 2.安装 MySQL 服务 3.安装配置 PHP 解析环境 4.部署 Discuz&#xff01;社区论坛 Web 应用 1.安装Nginx服务 实验准备 systemctl stop firewalld systemctl disable firewalld setenforce 0 安装依赖包 yum -y install pcre-devel zlib-devel gcc…

Linux_CentOS_7.9 VNC安装卸载以及相关配置开机自启动服务简易记录

VNC安装卸载以及相关配置开机自启动服务&#xff1a; 查看环境&#xff1a;&#xff08;yum镜像源配置可以参考我之前文章里面有详细参考http://t.csdnimg.cn/mzGoI&#xff09; [rootorcl238 ~]# rpm -qa | grep vnc ##查看系统现有VNC软件版本 gtk-vnc2-0.7.0-3.el7.x86…

DDD领域驱动设计系列-原理篇-战略设计

概述 DDD领域驱动设计是架构方法论&#xff0c;适用于业务逻辑较复杂系统。 DDD核心目的能输出领域如何划分&#xff0c;以及架构分层如何构建。 本文章系列会分2部分讲述DDD&#xff1a;1、DDD原理&#xff1b;2、DDD实践。DDD原理分为战略及战术设计2篇来讲述&#xff1b;…

TCP/IP的体系结构

目录 一、TCP/IP的体系结构 二、TCP/IP四层协议的表示方法举例 三、现在因特网使用的TCP/IP体系结构 四、互联网应用层的客户——服务器方式 一、TCP/IP的体系结构 二、TCP/IP四层协议的表示方法举例 三、现在因特网使用的TCP/IP体系结构 四、互联网应用层的客户——服务器…

CSK6环境搭建

前期准备 开发板测试 &#xff08;1&#xff09;根据这个视频教程来进行测试&#xff1a;示例工程快速上手 Ubuntu环境搭建 &#xff08;1&#xff09;聆思官方推荐使用Linux开发&#xff0c;因此我于是采用VMware搭建Ubuntu的方式进行开发。不清楚Ubuntu搭建的请看&#xff1…

Linux——缓冲区与实现C库的fopen,fwrite,fclose

目录 一.缓冲区 1缓冲区的概念 2.缓冲区存在的意义 3.缓冲区刷新策略 4.什么是刷新&#xff1f; C语言的缓冲区在哪里&#xff1f; ​编辑 仿写C库里的fopen&#xff0c;fclose&#xff0c;fwrite。 mystdio.h mystdio.c main.c(向文件中写入20次msg) 一.缓冲区 1…

stack容器

stack容器 文章目录 stack容器一、头文件二、stack基本概念三、stack常用接口 一、头文件 #include <stack>二、stack基本概念 概念: stack是一种先进后出(First In Last Out,FILO)的数据结构&#xff0c;它只有一个出口 栈中只有顶端的元素才可以被外界使用&#xff0…

C++『异常』

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f383;操作环境&#xff1a; Visual Studio 2022 版本 17.6.5 文章目录 &#x1f307;前言&#x1f3d9;️正文1.异常基本概念1.1.C语言异常处理方式1.2.C异常处理方式 2.异常的使用2.1.异常…

perl单行命令统计项目中代码单行过长的信息

项目中单行代码太长是不便于阅读和维护的&#xff0c;这里用perl单行命令实现项目中的单行过长的代码信息统计&#xff0c;方便修改。为方便说明&#xff0c;这里以一个开源项目为例&#xff0c;github链接evpp。以commit id 477033f938fd47dfecde43c82257cd286d9fa38e 为例&am…

陀螺仪LSM6DSV16X与AI集成(4)----Qvar触摸电容配置

陀螺仪LSM6DSV16X与AI集成.4--Qvar触摸电容配置 概述视频教学样品申请源码下载生成STM32CUBEMX串口配置IIC配置CS和SA0设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置Qvar 功能的实现和配置设置量程和速率配置过滤链激活 Qvar 功能获取Qvar数据演示 概述 Qvar&#x…

2-5、包含多个段的程序

语雀原文链接 文章目录 1、概述2、代码段中使用数据示例1&#xff1a;不指定程序入口示例2&#xff1a;指定程序入口原理梳理 3、在代码段中使用栈例子1例子2 4、数据、代码、栈放入不同的段例子1&#xff1a;end start指定程序入口第一步&#xff1a;设置栈顶第二步&#xff…

Golang channle(管道)基本介绍、快速入门

channel(管道)-基本介绍 为什么需要channel&#xff1f;前面使用全局变量加锁同步来解决goroutine的通讯&#xff0c;但不完美 1)主线程在等待所有goroutine全部完成的时间很难确定&#xff0c;我们这里设置10秒&#xff0c;仅仅是估算。 2)如果主线程休眠时间长了&#xff0c…

tgf - 一个开箱即用的golang游戏服务器框架

tgf框架 tgf框架是使用golang开发的一套游戏分布式框架.属于开箱即用的项目框架,目前适用于中小型团队,独立开发者,快速开发使用.框架提供了一整套开发工具,并且定义了模块开发规范.开发者只需要关注业务逻辑即可,无需关心用户并发和节点状态等复杂情况. 使用介绍 创建业务逻辑…