百万并发服务器设计

2023-11-08


前言

本文的基础以及使用的代码模型都继承自上一篇文章。所以请先详细阅读上篇文章。


提示:以下是本篇文章正文内容

如何在上篇文章的基础上使其支持百万并发。主要就是neyreactor结构体如何支持一百万个连接。上篇文章出现的 MAX_EPOLL_EVENTS 宏定义是1024,也就是上篇文章只支持1024个连接,这篇文章我们会将它改造成可以支持到百万连接。

1、改造ntyreactor

struct ntyreactor {
	int epfd;
	int blkcnt;
	struct eventblock *evblk;
};

把之前的一个ntyevent数组改成一个eventblock,blkcnt存储着链表块的长度。evblk它是一个链表,链表的结点存储这1024个ntyevent,定义如下

struct eventblock {

	struct eventblock *next;
	struct ntyevent *events;

};

2、如何管理eventblock

创建一个eventblock

int ntyreactor_alloc(struct ntyreactor *reactor) {

	if(reactor == NULL) return -1;
	if(reactor->evblk == NULL) return -1;

	struct eventblock* evblk = reactor->evblk;
	while (evblk->next != NULL)
	{
		evblk = evblk->next;
	}

	struct ntyevent *evs = (struct ntyevent *)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
	if (evs == NULL) {
		printf("ntyreactor_alloc ntyevent failed");
		return -2;
	}
	memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));

	struct eventblock *blk = (struct eventblock *)malloc(sizeof(struct eventblock));
	if (blk == NULL) {
		printf("ntyreactor_alloc eventblock failed");
		return 2;
	}
	memset(blk, 0, sizeof(struct eventblock));

	blk->events = evs;
	blk->next = NULL;
	evblk->next = blk;
	reactor->blkcnt++;

	return 1;
}

查找对应fd在那个eventblock上

struct ntyevent* ntyreactor_idx(struct ntyreactor *reactor, int sockfd)
{

	int blkidx = sockfd / MAX_EPOLL_EVENTS;

	while (blkidx >= reactor->blkcnt)
	{
		ntyreactor_alloc(reactor);
	}
	
	
	int i  = 0;

	struct eventblock *blk = reactor->evblk;

	while (i++ < blkidx && blk != NULL)
	{
		blk = blk->next;
	}
	
	return &blk->events[sockfd % MAX_EPOLL_EVENTS];

}

代码解读:

  1. 创建eventblock没什么好说的,就是初始化一个eventblock,并加入到reactor的evblk链表中,并且将blkcnt++;
  2. 如何查找一个fd在那个eventblock上,根据代码,首先整除1024,即可知道它在对应的那个eventblock上,如果找到的块的序号大于当前链表的块的数目的最大值,那么将创建eventblock块直到reactor->blkcnt等于blkidx。然后如何得到fd在对应块的第几个ntyevent上呢,没错,对其对1024取余。

具体使用

其实上面的代码已经将最初的Reactor改造成了一个可以支持百万并发的服务器了,其实它可以支持更多的连接,这取决于服务器的内存。如果内存够大,支持的连接数就越大,如果内存不够大,上面的代码能跑到50w,其实也就说明程序没有什么问题了。
好了,说回正题。如何使用这个链表呢,上篇文章将fd对应的ntyevent写入reactor和通过reactor找到对应fd的ntyevent的方式改为通过ntyreactor_idx函数获取到对应的结点进行写入和读取 。
比如对于将listenfd写入readcor:

int ntyreactor_addlistener(struct ntyreactor *reactor, int sockfd, NCALLBACK *acceptor) {

	if (reactor == NULL) return -1;
	if (reactor->evblk == NULL) return -1;

	struct ntyevent *event = ntyreactor_idx(reactor, sockfd);

	nty_event_set(event, sockfd, acceptor, reactor);
	nty_event_add(reactor->epfd, EPOLLIN, event);

	return 0;
}

recv_cb:

int recv_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	struct ntyevent *ev = ntyreactor_idx(reactor, fd);

	int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0);
	nty_event_del(reactor->epfd, ev);

	if (len > 0) {
		
		ev->length = len;
		ev->buffer[len] = '\0';

		printf("C[%d]:%s\n", fd, ev->buffer);

		nty_event_set(ev, fd, send_cb, reactor);
		nty_event_add(reactor->epfd, EPOLLOUT, ev);
		
		
	} else if (len == 0) {

		close(ev->fd);
		//printf("[fd=%d] pos[%ld], closed\n", fd, ev-reactor->events);
		 
	} else {

		close(ev->fd);
		printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
		
	}

	return len;
}

其他函数可以自己去修改。

3、总结

通过对之前Reactor模型的修改可以将服务器接受的并发量增加到百万甚至更多。但是仅仅对上面 的修改是不能接受那么多连接的,还需要修改一些地方:

  1. 进程需要监听更多的端口。根据四元组<sourceip,sourceport,dstip,dstport>可以知道,一个客户端,一个服务器,客户端端口最多可支持65535个,服务器端口1个,那么这种框架下最大支持60000多个客户端的连接,所以我们要监听更多的端口。
  2. 客户端需要地址复用以及打开多个客户端。这个只是为了可以让一个客户端生成更多的socket去连服务器。如果需要客户端代码可以私信我。
  3. 其次需要修改服务器的设置:
net.ipv4.tcp_mem = 262144 524288 786432
net.ipv4.tcp_wmem = 1024 1024 2048
net.ipv4.tcp_rmem = 1024 1024 2048
fs.file-max = 1048576

将读写缓冲区设置的小一些,这样一个连接使用的内存可以小一些,但是设置完之后仅限于测试百万连接,不然在其他应用中可能会出现问题。然后修改file-max,让进程可以打开的文件描述符数量支持到百万。

然后就尽情的测试吧!good luck。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

百万并发服务器设计 的相关文章

  • 将Ubuntu 的文件映射到windows 中

    可以通过Samba服务器将VM 下安装的Ubuntu 的文件映射到windows系统下 从而实现在windows下对虚拟机中的文件进行编辑 1 sudo apt get install samba 安装samba服务器 2 vim etc
  • Scala中的集合(容器)元素

    1 列表List https blog csdn net hzp666 article details 115004788 2 vector 向量 https blog csdn net hzp666 article details 115
  • Java多线程(面试)

    一 程序 进程与线程 程序 Program 程序是一段静态代码 进程 Process 进程是指一种正在运行的程序 有自己的地址空间 特点 动态性 并发性 独立性 并发和并行的区别 并发 多个cpu同时执行多个任务 并行 一个cpu同时执行多
  • TCP/IP网络编程之四书五经

    TCP IP网络编程之四书五经 http blog chinaunix net u 24935 showart 330099 html http book csdn net bookfiles 69 100691972 shtml http
  • python笔记8--命令行解析Argparse

    python笔记8 命令行解析Argparse 1 功能 2 源码案例 2 1 默认功能 2 3 添加说明 2 4 设置参数类型 2 5 设置参数可省略 2 6 同时存在可省略和必须参数 2 7 设置参数的范围 2 8 结束案例 3 说明

随机推荐

  • SpringBoot,或springcloud微服务项目前端Vue和后端java实现国际化

    外包公司接到了一个新加坡绿联国际银行的项目 有一个需求是要求实现国际化 像谷歌浏览器自带翻译那样 点按钮可以切换英文 繁体 中文来回切换这种效果 琢磨过之后找的资料最多的就是说用i18n 用i18n这个思路没问题 也很简单 下载一下i18n
  • Emqx的简单使用

    Emqx 是一个mqtt 的服务器产品 之前activemq可以作为mqtt协议的服务器 但是功能相对来说比较单一 Emqx作为跟Mqtt协议相关的新一代产品 功能实际上更为强大 它的功能也主要体现在可视化 认证 规则 httpApi 上面
  • MongoDB和Redis

    mongoDB基础语法 封装之后的查询 测试脚本 using System using YouYouServer Common using YouYouServer Common DBData using YouYouServer Core
  • javaweb (三)——javabean

    文章目录 1 1 javabean简介 1 2 javabean应用 1 2 1 javabean与表单 1 2 2 设置属性
  • 文献

    Hello 大家好 这里是壹脑云科研圈 我是墨心 你快乐吗 你想获得快乐吗 如果你不快乐 可能是因为你太想快乐了 这是一个 追求快乐 的悖论 Zerwas和Ford 2021 在Current Opinion in Behavioral S
  • chisel使用自定义/标准库中的函数简化设计(更新)

    主体内容摘自 https blog csdn net qq 34291505 article details 87905379 函数是编程语言的常用语法 即使是Verilog这样的硬件描述语言 也会用函数来构建组合逻辑 对于Chisel这样
  • powermill2020卡死_大家注意了!PowerMILL2020来了......

    欧克特官方已发布PowerMILL2020 机明软件为您预告PowerMILL2020的部分新增功能及部分功能的优化 一 刀具路径改进 1 上坡清角精加工 当使用清角精加工策略时 选择上坡切削 这样在陡峭区域的拐角将由下向上而不是由上向下加
  • 马斯克又出昏招、最疯狂的举动之一!给不喜欢的网站增加5秒延迟

    编译 核子可乐 Tina 马斯克正在限制他不喜欢的新闻网站和竞争对手的流量 在 X 原 Twitter 上点击纽约时报 路透社 Facebook Instagram Threads Bluesky 和 Substack 的链接 X 故意增加
  • git的使用——最全操作流程

    目录 一 什么是git 二 添加SSH公钥 三 gitee创建仓库 四 git操作 1 git常用命令 2 用一张图来简单解释一下操作流程 3 流程详解 一 什么是git git是一个开源的分布式版本控制软件 能够有效并高效的处理很小到非常
  • Python学习之路:time和datetime模块

    转自 http blog 51cto com egon09 1840425 一 内建模块 time和datetime http www jb51 net article 49326 htm 在Python中 通常有这几种方式来表示时间 1
  • 加速Nerf训练:nerfacc

    加速Nerf训练 nerfacc 0 引言 1 NerfAcc加速原理 1 1 跳过空区域与遮挡区域 Pruning Empty and Occluded Regions 1 2 GPU层面 1 3 场景压缩 Scene Contracti
  • MongoDB连接本地失败解决办法

    MongoDB连接本地失败解决办法 错误原因 解决办法 在mongodb目录中新建一个data文件夹 如果有就不用建 进入data文件夹 建立db和log两个文件夹 如果有就不用新建 打开CMD 进入到mongodb 的 bin目录 输入指
  • Spring 中的 @Cacheable 缓存注解,太好用了!

    1 什么是缓存 第一个问题 首先要搞明白什么是缓存 缓存的意义是什么 对于普通业务 如果要查询一个数据 一般直接select数据库进行查找 但是在高流量的情况下 直接查找数据库就会成为性能的瓶颈 因为数据库查找的流程是先要从磁盘拿到数据 再
  • 彩虹6号怎么修改服务器,彩虹6号修改服务器地址

    彩虹6号修改服务器地址 内容精选 换一换 修改云服务器信息 目前支持修改云服务器名称及描述和hostname 该接口支持企业项目细粒度权限的校验 具体细粒度请参见 ecs cloudServers put云服务器hostname修改后 需要
  • C#常见简答题

    静态类和静态方法的好处与缺陷 1 好处是 在外部调用静态方法时 可以使用 类名 方法名 的方式 也可以使用 对象名 方法名 的方式 而实例方法只有后面这种方式 也就是说 调用静态方法可以无需创建对象 2 缺陷是 静态方法在访问本类的成员时
  • .el-dialog弹窗垂直居中(重点::兼容IE)

    el dialog display flex display ms flex 兼容IE flex direction column ms flex direction column 兼容IE margin 0 important posit
  • 浮点数与数组的转换

    一 指针方式 include
  • Servlet+JDBC实战开发书店项目讲解第12讲:会员管理功能

    Servlet JDBC实战开发书店项目讲解第12讲 会员管理功能 实现思路 显示会员列表 创建一个管理页面 用于显示所有会员的信息 在后端 创建一个Servlet来处理显示会员列表的请求 在该Servlet中 通过JDBC从数据库中检索会
  • MinGW、GCC、qMake等编译工具的区别

    MSVC在Windows下编译C和C gcc g 分别是GNU的C 和 C 编译器 在Linux 下面用 cmake qmake分别用来编译C和QT工程 输入是makefile 输出结果是可执行文件 编译的过程会调用编译器和连接器来完成整个
  • 百万并发服务器设计

    文章目录 前言 1 改造ntyreactor 2 如何管理eventblock 创建一个eventblock 查找对应fd在那个eventblock上 具体使用 3 总结 前言 本文的基础以及使用的代码模型都继承自上一篇文章 所以请先详细阅