Linux网络编程 - I/O多路复用之epoll
目录
- 什么是epoll?
- 为什么要使用epoll?
- 如何使用epoll?
- 查看epoll官方帮助文档
- epoll版TCP回音客户端
- epoll版TCP回音服务端
<一> 什么是epoll?
epoll = enhance poll 增强版轮询,是poll/select 的升级版;
<二> 为什么要使用epoll?
使用epoll在对fd进行监视时,如果有满足条件的fd,则该fd会被添加到一个新的数组区域,该区域存放所有满足条件的fd;
获取/判断满足条件的fd时,遍历当前数组即可;
但上述原理和select原理基本一致,那epoll增强了什么?
epoll在轮询(poll)时,提供了两种触发方式:
- Level Triggered 水平触发(EPOLLLT)
- Edge Triggered 边缘触发(EPOLLET)
水平触发(LT):
对于一文件描述符fd=0,在被epoll监视时,若采用LT则在read函数读入数据,若buffer大小 < read内容大小,则在下一次使用read时,epoll会通知read读取上一次剩余的内容(epoll缺省配置);
边缘触发(ET):
相较于上述LT中示例,边缘触发在下一次使用read0时,epoll不会再通知read0中有数据可读,即再次读取一次新的数据,原有read(0,buffer,sizeof(buffer)) 中大于sizeof(buffer)的内容将被丢弃;
边缘:每次读或写作为一个边缘,遇到边缘只通知一次,随后不再处理边缘文件描述符。
<三> 如何使用epoll?
1> 首先需要创建一个epoll文件描述符,指定epoll可以监视fd的最大值
#define MAX_EVENTS 10
int epfd = epoll_create(MAX_EVENTS);
if(epfd == -1){
perror("epoll_create"); //stdio.h
exit(EXIT_FAILURE); //stdlib.h
}
2> 指定需要监视fd的活动(读/写/...)
struct epoll_event ev, events[MAX_EVENTS];
int fd = 0;
ev.events = EPOLLIN|EPOLLET;
ev.data.fd = fd;
3> 将指定活动添加进入epoll实例
if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,ev) == -1){
perror("epoll_ctl:0");
exit(EXIT_FAILURE);
}
4> 使用循环,开启epoll监视
for(;;){
int num = epoll_wait(epfd,rev,MAX_EVENTS,-1);
if(num == -1){
perror("epoll_wait");
break;
}
//...
int i=0;
for(;i<num;i++){
if(events[i].data.fd == fd){
size = read(0,buffer,sizeof(buffer));
}
//...
}
}
<四> 查看epoll官方帮助文档
man 2 epoll
<五> epoll版TCP回音客户端
客户端处理函数:
Client 边缘触发示例,用于边缘触发本地输入与客户端对socket的读取;
本示例无法解决客户端 "粘包" 问题;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_EVENTS 2
/* 服务器对客户端请求的处理 */
void server_process(int sc){
int size = 0;
char buffer[1024];
for(;;){
size = read(sc,buffer,sizeof(buffer));
if(size == 0){
return;
}
write(sc,buffer,size);
write(1,buffer,size);
memset(buffer,0,sizeof(buffer));
}
}
/* 客户端处理数据 */
void client_process(int ss){
int size = 0;
char send_buffer[1024]; //发送缓冲区1K
char recv_buffer[5]; //接收缓冲区5B
int epfd = epoll_create(2);
int fd = 0;
struct epoll_event ev1,ev2;
struct epoll_event events[MAX_EVENTS];
ev1.data.fd = fd;
ev1.events = EPOLLIN|EPOLLET;
ev2.data.fd = ss;
ev2.events = EPOLLIN|EPOLLET;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev1)==-1){
perror("epoll_ctl:0");
exit(EXIT_FAILURE);
}
if(epoll_ctl(epfd,EPOLL_CTL_ADD,ss,&ev2)==-1){
perror("epoll_ctl:ss");
exit(EXIT_FAILURE);
}
memset(send_buffer,0,sizeof(send_buffer));
memset(recv_buffer,0,sizeof(recv_buffer));
for(;;){
int num = epoll_wait(epfd,events,MAX_EVENTS,-1);
if(num == -1){
perror("epoll_wait");
exit(EXIT_FAILURE);
}
int i=0;
for(;i<num;i++){
int tfd = events[i].data.fd;
if(tfd == fd){
size = read(fd,send_buffer,sizeof(send_buffer));
write(ss,send_buffer,size);
memset(send_buffer,0,sizeof(send_buffer));
}else
if(tfd == ss){
printf("++++\n");
size = read(ss,recv_buffer,sizeof(recv_buffer));
write(1,recv_buffer,size);
memset(recv_buffer,0,size);
}
}
}
}
上一篇: 7个超级实用的PHP代码片段
下一篇: PHP常用正则表达式汇总_PHP教程
推荐阅读
-
Linux IO多路复用之epoll网络编程
-
python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)
-
Linux网络编程 - I/O多路复用之epoll
-
Linux系统编程——I/O多路复用select、poll、epoll的区别使用
-
【Linux网络编程】基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型
-
Linux网络编程【五】:TCP协议高性能服务器(http)模型之I/O多路转接select
-
LINUX 网络编程---多路复用和信号驱动I/O(王德仙)2012-04-07 客户端和服务器端编写完成,明天开始学习poll 和epoll...
-
Linux网络编程 之 IO多路复用poll(九)
-
Linux IO多路复用之epoll网络编程