说明

一直听说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的饥饿场景的更多相关文章

  1. FastAPI(38)- 模拟一个跨域场景

    同源策略 https://www.cnblogs.com/poloyy/p/15345184.html CORS https://www.cnblogs.com/poloyy/p/15345871.h ...

  2. Jmeter中模拟多用户执行多场景操作

    1.其实一个用户组就是一个场景(Thread Group).可以在一个测试计划中进行多个场景的执行,在测试计划下加一个全局的User Defined Variables,在这个里面可以设置执行总数to ...

  3. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  4. Dummynet模拟高时延网络场景(Windows7)

    如果安装时出现:my_socket failed 2, cannot talk to kernel module 请查看是否以管理员方式运行,如果是,再判断当前操作系统是否为Win7 64位,如果是, ...

  5. Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  6. 【转】 Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  7. [Bullet3]创建世界(场景)及常见函数

    创建世界(场景)及常见函数 官方文档:http://bulletphysics.org 开源代码:https://github.com/bulletphysics/bullet3/releases A ...

  8. SoapUI模拟REST MockService

    一.新建REST工程 二.添加URI 物流查询接口测试地址:http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号 三.输入入参,测试一下 ...

  9. 消息中间件activemq的使用场景介绍(结合springboot的示例)

    一.消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩和最终一致性架构.是大型分布式系统不可缺少的中间件. 目前在生产环境,使 ...

  10. I/O模型系列之五:IO多路复用 select、poll、epoll

    IO多路复用之select.poll.epoll IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. 应用:适用于针 ...

随机推荐

  1. 客户端单元测试实践——C++篇

    简介: 我们团队在手淘中主要负责BehaviX模块,代码主要是一些逻辑功能,很少涉及到UI,为了减少双端不一致问题.提高性能,我们采用了将核心代码C++化的策略.由于团队项目偏底层,测试同学难以完全覆 ...

  2. 高德AR驾车导航解决方案

    简介: 高德从2018年首创了车载AR导航后,已经先后在后视镜.智能车盒.前装整车厂.后装车机产品.行车记录仪等众多场景落地应用,搭建了非常完整的AR导航生态. 日前,高德地图最新发布了v10.60新 ...

  3. 【产品能力深度解读】连续入围Gartner魔力象限的Quick BI有何魔力?

    简介: 国际权威分析机构Gartner发布2021年商业智能和分析平台魔力象限报告,阿里云Quick BI再度入选,并继续成为该领域魔力象限唯一入选的中国企业. Quick BI凭借在增强分析能力上的 ...

  4. [FAQ] FinalCutPro 事件如何支持多个时间线

    左侧是建立的事件,右侧是默认的项目(也就是时间线上的剪辑项目). 如果需要这个事件里再弄一个时间线(比如剪辑另一个版本),左侧的事件上右击新建项目: 另一个项目,在这上面可以继续时间线的创作,等于是选 ...

  5. [Go] gorm 返回指定模型数据的处理方式

    重新 var 声明一个变量,类型为包含指定字段的结构体. 查询的时候,还是使用原始模型类型的变量. example: // For return data var retMember struct { ...

  6. 通过WebRTC简单实现媒体共享

    通过WebRTC简单实现媒体共享 媒体协商 在设置本地描述符(offer/answer)前,我们总是需要将媒体添加到连接中,只有这样在描述符中才能包含需要共享的媒体信息,除非你不需要共享媒体. 在实际 ...

  7. K8s集群中部署SpringCloud在线购物平台(二)

    三.harbor简介 harbor 是私有镜像仓库,用来存储和分发镜像的 docker 还有一个官方的镜像仓库 docker hub,免费用户只能简单的使用,创建一个私有镜像仓库,存储 镜像,付费用户 ...

  8. netcore5下ocelot网关简单使用

    1.新建aspnetcoremvc项目,带home控制器的就可以了,测试用能启动就行,代码无需做任何更改. 2.新建空的aspnetcoremvc项目,做如下更改: 1..  2.. 3..  4.. ...

  9. 一个开源轻量级的C#代码格式化工具(支持VS和VS Code)

    前言 C#代码格式化工具除了ReSharper和CodeMaid,还有一款由.NET开源.免费(MIT License).轻量级的C#语言代码格式化工具:CSharpier. 工具介绍 CSharpi ...

  10. 报错:Client does not support authentication protocol requested by server; consider upgrading MySQL cli

    IDEA启动项目登录时显示用户或密码错误 或者 连接mysql数据库时报错 原因: mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是ca ...