当前位置:网站首页>socket编程——epoll模型
socket编程——epoll模型
2022-06-25 08:07:00 【编程小段】
利用epoll模型实现多个客户端和一个服务端的CS模型——多路IO复用技术
epoll优点
- select和poll是线性处理,而epoll是红黑树处理
- select和poll频繁的在内核和用户区进行拷贝,而epoll使用的是共享内存
- 程序需要对select和poll返回的集合进行判断才能知道哪些文件描述符是就绪的,但epoll可以直接得到已就绪的文件描述符集合,无需再次检测
- epoll
将检测文件描述符的变化委托给内核去处理,然后内核将发生变化的描述符对应的事件返回给程序。不仅告诉程序有几个发生变化,而且精准的告诉程序哪几个发生变化
创建一棵epoll树
int epoll_create(int size);
param:
size: 最大节点数,需要传递大于0的数,linux上该参数被忽略
return:
成功:返回大于0的文件描述符,代表整个树的树根
失败:返回-1
将要监听的节点在epoll树上添加、删除和修改
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
param:
epfd:epoll_create函数的返回值
op: EPOLL_CTL_ADD: 往 epoll 模型中添加新的节点
EPOLL_CTL_MOD: 修改 epoll 模型中已经存在的节点
EPOLL_CTL_DEL: 删除 epoll 模型中的指定的节点
fd:要操作的文件描述符
event:检测这个文件描述符的什么事件
event.events:委托 epoll 检测的事件
EPOLLIN:读事件,接收数据,检测读缓冲区
EPOLLOUT:写事件,发送数据,检测写缓冲区
EPOLLERR:异常事件
event.data:通常情况下使用里边的fd成员,委托内核监控的文件描述符,在调用 epoll_wait函数的时候这个值会被传出
return:
成功:返回 0
失败:返回 - 1
委托内核监控epoll实例中有没有就绪的文件描述符
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
param:
epfd: epoll_create函数的返回值,通过这个参数找到 epoll 实例
events: 传出参数,里边存储了已就绪的文件描述符的信息
maxevents: 修饰第二个参数,结构体数组的容量(元素个数)
timeout: 0:函数不阻塞
>0:函数阻塞对应的毫秒数再返回
-1:函数一直阻塞,直到 epoll 实例中有已就绪的文件描述符之后才解除阻塞
服务端代码如下,客户端代码不变
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<netinet/in.h>
#include<errno.h>
#include<sys/epoll.h>
int main()
{
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd < 0)
{
perror("socket error");
return -1;
}
struct sockaddr_in serv;
bzero(&serv, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
if(ret < 0)
{
perror("bind error");
return -1;
}
listen(lfd, 128);
//创建一棵epoll树
struct epoll_event ev;
struct epoll_event events[1024];
int epfd = epoll_create(1024);
if(epfd < 0)
{
perror("create epoll error");
return -1;
}
//将监听文件描述符上树
ev.data.fd = lfd;
ev.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
int nready;
int max=0;//表示内核监控的范围,一开始有1个
int cfd;
int sockfd;
int i;
int n;
char buf[1024];
while(1)
{
nready = epoll_wait(epfd, events, 1024, -1);
if(nready < 0)
{
if(errno == EINTR)
continue;
perror("epoll wait error\n");
break;
}
for(i=0; i<nready; i++)
{
//有客户端连接请求到来
sockfd = events[i].data.fd;
if(sockfd == lfd)
{
cfd = accept(lfd, NULL, NULL);
//将新的cfd上树
ev.data.fd = cfd;
ev.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
continue;
}
//有数据发来
memset(buf, 0, sizeof(buf));
//n = read(sockfd, buf, sizeof(buf));
n = recv(sockfd, buf, sizeof(buf), 0);
if(n <= 0)
{
close(sockfd);
//将sockfd对应的事件的节点从epoll树上删除
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
printf("read error or client close\n");
continue;
}
printf("n == [%d], buf == [%s]\n", n, buf);
for(int j=0; j<n; j++)
{
buf[j] = toupper(buf[j]);
}
//write(sockfd, buf, n);
send(sockfd, buf, n, 0); }
}
close(epfd);
close(lfd);
return 0;
}
扩展:
epoll的ET(边沿触发) 和 LT(水平触发) 模式
- epoll默认情况下是LT模式,在这种模式下,若读数据一次性没有读完,缓冲区还有可读数据,则epoll_wait还会通知(比如发10个数据,一次只读两次,那么会循环读取5次)
- 若将epoll设置为ET模式(ev.events = EPOLLIN | EPOLLET),若读数据的时候一次性没有读完,则epoll_wait不再通知,直到下次有新的数据发来(还会读取上一次缓冲区已收到但还未读走的数据)
边栏推荐
- 紧急行政中止令下达 Juul暂时可以继续在美国销售电子烟产品
- [MySQL] understanding of transactions
- Wechat applet_ 7. Project practice, local life
- 进击的技术er,遇见实习岗位信息
- How safe is the new bond
- C language: count the number of words in a paragraph
- 【强化学习笔记】强化学习中的常见符号
- 关于I/O——内存与CPU与磁盘之间的关系
- [515. find the maximum value in each tree row]
- Advanced technology Er, meet internship position information
猜你喜欢

如何成为一名软件测试高手? 月薪3K到17K,我做了什么?

EasyPlayer流媒体播放器播放HLS视频,起播速度慢的技术优化

What do various optimizers SGD, adagrad, Adam and lbfgs do?

How to become a software testing expert? From 3K to 17k a month, what have I done?

About i/o -- the relationship between memory and CPU and disk

A 35 year old Tencent employee was laid off and sighed: a suite in Beijing, with a deposit of more than 7 million, was anxious about unemployment

Lvs-dr mode multi segment case

【无标题】**数据库课设:三天完成学生信息管理系统**

How to design test cases

Find the nearest common ancestor (Sword finger offer) of two nodes in the binary tree (search tree)
随机推荐
Is it safe to open a stock account online now?
[reinforcement learning notes] common symbols in reinforcement learning
flutter 获取顶部状态栏的高度
城鏈科技平臺,正在實現真正意義上的價值互聯網重構!
IC研发常用英文术语缩写
Stimulsoft Ultimate呈现报告和仪表板
LVS-DR模式单网段案例
How to solve the 10061 error of MySQL in Linux
二、训练fashion_mnist数据集
C language "Recursion Series": recursively realizing the n-th power of X
Similarity calculation method
关掉一个线程
各种同步学习笔记
打新债真的安全吗? 风险大吗
Various synchronous learning notes
Retrieval model rough hnsw
紧急行政中止令下达 Juul暂时可以继续在美国销售电子烟产品
tp6自动执行的文件是哪个?tp6核心类库有什么作用呢?
进击的技术er,遇见实习岗位信息
五、项目实战---识别人和马