模拟epoll的饥饿场景
说明
一直听说epoll的饥饿场景,但是从未在实际环境中面对过,那么能不能模拟出来呢?实际的情况是怎样呢?
模拟步骤
- 基于epoll写一个简单的tcp echo server,将每次read返回的字节数打印出来
- 模拟一个客户端大量写入
- 测试其他客户端能否正常返回
Server代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_EVENTS 1024
#define LISTEN_BACKLOG 10
int epoll_fd;
void do_read(int fd);
int main() {
int server_fd, nfds, i;
struct epoll_event event, events[MAX_EVENTS];
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd;
// 创建 socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket");
return 1;
}
// 设置 socket 选项
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
perror("setsockopt");
close(server_fd);
return 1;
}
// 绑定 socket
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8080);
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
close(server_fd);
return 1;
}
// 监听 socket
if (listen(server_fd, LISTEN_BACKLOG) == -1) {
perror("listen");
close(server_fd);
return 1;
}
// 创建 epoll 实例
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1");
close(server_fd);
return 1;
}
// 注册服务器 socket
event.events = EPOLLIN;
event.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {
perror("epoll_ctl");
close(server_fd);
close(epoll_fd);
return 1;
}
printf("Server listening on port 8080...\n");
while (1) {
// 等待事件就绪
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
close(server_fd);
close(epoll_fd);
return 1;
}
// 处理就绪事件
for (i = 0; i < nfds; i++) {
if (events[i].data.fd == server_fd) {
// 接受新连接
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_fd == -1) {
perror("accept");
continue;
}
if (fcntl(client_fd , F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl");
close(client_fd);
continue;
}
// 注册客户端 socket
event.events = EPOLLIN;
event.data.fd = client_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) {
perror("epoll_ctl");
close(client_fd);
continue;
}
printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
} else {
do_read(events[i].data.fd);
}
}
}
close(server_fd);
close(epoll_fd);
return 0;
}
void do_read(int fd) {
// 处理客户端数据
char buf[1024];
while(1) {
ssize_t bytes_read = read(fd, buf, sizeof(buf));
if (bytes_read == -1) {
perror("read");
close(fd);
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1) {
perror("epoll_ctl");
}
break;
} else if (bytes_read == 0) {
printf("Client disconnected\n");
close(fd);
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1) {
perror("epoll_ctl");
}
break;
} else {
printf("Received data: %d\n", bytes_read);
if (write(fd, buf, bytes_read) != bytes_read) {
perror("write");
close(fd);
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1) {
perror("epoll_ctl");
}
break;
}
if (bytes_read < 1024) {
break;
}
}
}
}
模拟客户端
客户端1:大量写入客户端:
cat /dev/random 2>/dev/null | nc 127.0.0.1 8080 >/dev/null
客户端2:其他写入客户端,少量写入检查返回值
nc 127.0.0.1 8080
模拟结果
- server端收到大量的数据,每次read返回1024个字节,句柄非常忙碌
- 客户端2往server发送的数据一直没有返回【处于饥饿状态】
- 一旦客户端1断开,客户端2就收到回复了
结果分析
从代码中可以知道,read一直都有数据读取,一直在处理数据,导致其他句柄无法处理数据。也就是说,其实是我们的代码造成了所谓的饥饿,那么也可以从我们的代码层面上去解决这个问题,思路官方man page中已经提到了,将fd维护一个list,均匀的读写数据即可。
模拟epoll的饥饿场景的更多相关文章
- FastAPI(38)- 模拟一个跨域场景
同源策略 https://www.cnblogs.com/poloyy/p/15345184.html CORS https://www.cnblogs.com/poloyy/p/15345871.h ...
- Jmeter中模拟多用户执行多场景操作
1.其实一个用户组就是一个场景(Thread Group).可以在一个测试计划中进行多个场景的执行,在测试计划下加一个全局的User Defined Variables,在这个里面可以设置执行总数to ...
- 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法
数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...
- Dummynet模拟高时延网络场景(Windows7)
如果安装时出现:my_socket failed 2, cannot talk to kernel module 请查看是否以管理员方式运行,如果是,再判断当前操作系统是否为Win7 64位,如果是, ...
- Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用
一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...
- 【转】 Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用
一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...
- [Bullet3]创建世界(场景)及常见函数
创建世界(场景)及常见函数 官方文档:http://bulletphysics.org 开源代码:https://github.com/bulletphysics/bullet3/releases A ...
- SoapUI模拟REST MockService
一.新建REST工程 二.添加URI 物流查询接口测试地址:http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号 三.输入入参,测试一下 ...
- 消息中间件activemq的使用场景介绍(结合springboot的示例)
一.消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩和最终一致性架构.是大型分布式系统不可缺少的中间件. 目前在生产环境,使 ...
- I/O模型系列之五:IO多路复用 select、poll、epoll
IO多路复用之select.poll.epoll IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. 应用:适用于针 ...
随机推荐
- 作业帮基于 DeltaLake 的数据湖建设最佳实践
简介:作业帮是一家以科技为载体的在线教育公司,其大数据中台作为基础系统中台,主要负责建设公司级数仓,向各个产品线提供面向业务主题的数据信息.本文主要分享了作业帮基于 DeltaLake 的数据湖建设 ...
- 数据的“敏捷制造”,DataWorks一站式数据开发治理范式演进
简介: 企业大数据技术发展至今,历经了两次蜕变.第一次蜕变从最初的"小作坊"解决大数据问题,到后来企业用各类大数据技术搭建起属于自己的"大平台",通过平台化的能 ...
- Flink 1.13,面向流批一体的运行时与 DataStream API 优化
简介: 在 1.13 中,针对流批一体的目标,Flink 优化了大规模作业调度以及批执行模式下网络 Shuffle 的性能,以及在 DataStream API 方面完善有限流作业的退出语义. 本文由 ...
- [FAQ] Python的虚拟环境和包管理
1. 创建虚拟环境 $ python -m venv test-env 2. 激活虚拟环境 windows:tutorial-env\Scripts\activate (powershell: . ...
- [K8s] Docker 单节点部署 Rancher
Rancher 是通过 Web 界面管理 k8s 集群的工具,本身支持使用 Docker 启动. 单节点部署只需要 docker run 即可,易用性高,高可用部署可以使用 nginx 反向代理机制. ...
- WPF 如何获取有哪些 VisualBrush 用了某个控件
我写了一个特殊的控件,我期望了解到有哪些 VisualBrush 捕获了此控件,或者说有哪些 VisualBrush 用了此控件的界面 本文的方法需要用到反射,需要使用 WPF 框架里面没有公开的字段 ...
- redis系列02---缓存过期、穿透、击穿、雪崩
一.缓存过期 问题产生的原由: 内存空间有限,给缓存设置过期时间,但有些键值运气比较好,每次都没有被我的随机算法选中,每次都能幸免于难,这可不行,这些长时间过期的数据一直霸占着不少的内存空间! 解决方 ...
- 259k+ Star!这是我见过最全的开发者技术学习路线!
大家好,我是 Java陈序员. 自从上班后,身体是一天不如一天了,也很少有时间可以去学习新技术了.程序员如果技术跟不上,很容易就被淘汰. 而碎片化的学习效率又不高,往往今天学了,明天就忘了.有时候更是 ...
- Linux定时任务实现每秒执行一次
编写/root/test.sh脚本 该方法适用于调度周期能被60整除的情况 #!/bin/bash step=1 for (( i = 0; i < 60; i = (i+step) )); d ...
- fastposter v2.8.4 发布 电商海报生成器
fastposter v2.8.4 发布 电商海报生成器 fastposter海报生成器,电商海报编辑器,电商海报设计器,fast快速生成海报 海报制作 海报开发.贰维海报,图片海报,分享海报贰维码推 ...