epoll介绍

1、epoll的优点(与select、poll对比)

i、支持一个进程打开大数目的socket描述符;

select()所支持打开的FD是有一定限制,FD_SETSIZE默认值是1024/2048。epoll没有描述符数量限制,一般是1G内存可以有10万左右,可通过使用cat /proc/sys/fs/file-max查看。

ii、IO效率不随FD数目增加面线性下降;

select/poll每次调用都会线性扫描全部的集合(同时还会轮询),导致效率呈现线性下降。而epoll不存在这个问题,因为epoll会为每个描述符FD注册一个回调函数,只有“活跃”的socket才会主动调用callback函数,其他idle状态socket则不会。当调用callback函数的FD,才返回相应的事件。

iii、使用mmap加速内核与用户空间的消息传递;

select、poll、epoll都需要内核把fd消息通知给用户空间。而epoll通过内核与用户空间mmap处于同一块内存实现消息的传递。

2、实现epoll的相关接口函数

epoll_create函数

#include
int epoll_create(int size);//告诉内核监听fd的数目
		//返回一个epoll句柄epfd,后续均要用着,在使用完epoll后,必须调用close关闭epfd,否则可能导致fd被耗尽

epoll_ctl事件注册函数

#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);

struct epoll_event {
	_uint32_t event;//Epoll events
	epoll_data_t data;//User data variable
};
typedef union epoll_data {
	void* ptr;
	int fd;
	uint32_t u32;
	uint64_t u64;
}epoll_data_t;

此函数先要注册要监听的事件类型(如listenfd);

第一个参数是epoll_create()的返回值;

第二个参数表示动作,用3个宏来表示:

1、EPOLL_CTL_ADD,注册新的fd到epfd中;

2、EPOLL_CTL_MOD,修改已经注册的fd的监听事件;

3、EPOLL_CTL_DEL,从epfd中删除一个fd;

第三个参数是需要监听的fd

第四个参数 告诉内核需要监听什么事,其中struct epoll_event结构体中的events可以是以下几个宏的集合,EPOLLIN(表示对应文件描述符可以读(包括对端socket正常关闭)),EPOLLOUT(表示对应文件描述符可以写),EPOLLPRI(表示对应文件描述符有紧急的数据可读),EPOLLERR(表示对应文件描述符发生错误),EPOLLHUP(表示对应文件描述符被挂断),EPOLLET(将EPOLL设为边缘触发模式,这是相对水平触发而言),EPOLLONESHOT(只监听一次事件,当监听完这次事件后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里)。

epoll_wait等待事件发生函数

#include
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);//等待事件的发生
				//返回需要处理的事件数目,返回0表示已超时

参数events(结构数组)用来从内核得到事件的集合,maxevents告诉内核这个events有多大,且maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时间(ms为单位,0会立即返回,-1将不确定或称永久阻塞)。

3、利用epoll编写一个回谢服务器

#include
#include
#include
#include
#include
#include
#include
#include

#define IPADDRESS "127.0.0.1"
#define PORT 9877
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE	1000
#define EPOLLEVENTS 100

#define SA struct sockaddr


void add_event(int epollfd,int fd,int state);
void handle_events(int epollfd,struct epoll_event* events,int num,int listenfd,char* buf);
void handle_accpet(int epollfd,int listenfd);
void do_read(int epollfd,int fd,char* buf);
void do_write(int epollfd,int fd,char* buf);
void delete_event(int epollfd,int fd,int state);
void modify_event(int epollfd,int fd,int state);

int main(){
	int listenfd,epollfd;
	struct sockaddr_in serv;
	struct epoll_event events[EPOLLEVENTS];
	char buf[MAXSIZE];
	int ret;
	

	listenfd=socket(AF_INET,SOCK_STREAM,0);
	
	bzero(&serv,sizeof(serv));
	serv.sin_family=AF_INET;
	serv.sin_port=htons(PORT);
	serv.sin_addr.s_addr=htonl(INADDR_ANY);
	
	bind(listenfd,(SA*)&serv,sizeof(serv));
	listen(listenfd,LISTENQ);

	bzero(buf,MAXSIZE);
	epollfd=epoll_create(FDSIZE);//create a fd. FDSIZE represent the maximum number of fd.
	add_event(epollfd,listenfd,EPOLLIN);//add fd(listenfd) to epollfd
	while(true){
		ret=epoll_wait(epollfd,events,EPOLLEVENTS,-1);//-1 representnever block.
		hand_events(epollfd,events,ret,listenfd,buf);
	}
	close(epollfd);
}
/*
struct epoll_event{
	_uint32_t events;//Epoll events
	epoll_data_t data;//User data variable
};

typedef union epoll_data{
	void* ptr;
	int fd;
	uint32_t u32;
	uint64_t u64;
}epoll_data_t;
*/


void add_event(int epollfd,int fd,int state){
	struct epoll_event ev;
	ev.events=state;
	ev.data.fd=fd;
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);//epoll事件注册函数,表明监听何种类型的事件
}

void hand_events(int epollfd,struct epoll_event *events,int num,int listenfd,char* buf){
	int fd;
	for(int i=0;i

4、利用epoll编写一个客户端(大多数代码参照服务器)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define IPADDRESS "127.0.0.1"
#define SERV_PORT 9877
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE	1000
#define EPOLLEVENTS 100

#define SA struct sockaddr


void add_event(int epollfd,int fd,int state);
void handle_events(int epollfd,struct epoll_event* events,int num,int listenfd,char* buf);
void handle_accpet(int epollfd,int listenfd);
void do_read(int epollfd,int fd,char* buf);
void do_write(int epollfd,int fd,char* buf);
void delete_event(int epollfd,int fd,int state);
void modify_event(int epollfd,int fd,int state);

int count=0;
int main(int argc,char* argv[]){
	int sockfd,epollfd;
	struct sockaddr_in serv;
	struct epoll_event events[EPOLLEVENTS];
	char buf[MAXSIZE];
	int ret;
	

	sockfd=socket(AF_INET,SOCK_STREAM,0);
	
	bzero(&serv,sizeof(serv));
	serv.sin_family=AF_INET;
	serv.sin_port=htons(SERV_PORT);
	inet_pton(AF_INET,IPADDRESS,&serv.sin_addr);

	connect(sockfd,(SA*)&serv,sizeof(serv));

	
	epollfd=epoll_create(FDSIZE);
	add_event(epollfd,STDIN_FILENO,EPOLLIN);
	for(;;){
		ret=epoll_wait(epollfd,events,EPOLLEVENTS,-1);
		handle_events(epollfd,events,ret,sockfd,buf);	
	}
	close(sockfd);
}



void add_event(int epollfd,int fd,int state){
	struct epoll_event ev;
	ev.events=state;
	ev.data.fd=fd;
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
}

void hand_events(int epollfd,struct epoll_event *events,int num,int sockfd,char* buf){
	int fd;
	for(int i=0;i

 

你可能感兴趣的:(socket,network,programming)