Linux I/O复用技术---epoll

1.介绍

 epoll和之前介绍的select/poll有很大的差异,几乎现在所有的高并发I/O模型都使用epoll(如nginx)。

  #include <sys/epoll.h>

  int epoll_create(int size);

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

  int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

 接下来逐一介绍这3个API:

(1)epoll_create    创建一个epoll

int epoll_create(int size);

    参数:

 

  • size       在Linux 2.6.8版本后没有实际意义,但是必须填大于0的数。成功返回非负值,错误返回-1。

(2)epoll_ctl   设置创建的epoll

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

   参数:

  • epfd  epoll_create的返回值
  • op  对一个fd,在epoll的操作类型:EPOLL_CTL_ADD(添加)、 EPOLL_CTL_MOD(修改)、  EPOLL_CTL_DEL(删除)
  • fd  要操作的fd
  • event

struct epoll_event的结构体描述如下:

struct epoll_event {
               uint32_t     events;      /* Epoll events */
               epoll_data_t data;        /* User data variable */
           };

    epoll_data_t定义如下:

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

epoll_ctl 成功返回0,错误返回-1。

(3)epoll_wait  检测事件。

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

参数:

  • epfd  上文中的epollfd
  • events  输出参数,存放事件信息的数组
  • maxevents 数组的个数
  • timeout 超时,单位为毫秒

epoll_wait 成功会返回事件的 fd 数目;返回 0 表示超时;失败返回 -1。

2.编码实战

#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<sys/epoll.h>


int main(int argc, char* argv[]){

int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0){
	printf("create socket failed!, errno=%d\n",errno);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);

int ret;
ret = bind(fd, (struct sockaddr*) &addr, sizeof(addr));
if(ret == -1){
	printf("bind failed!, errno=%d",errno);
	close(fd);
}
ret = listen(fd, SOMAXCONN);
if(ret == -1){
	printf("listen failed!, errno=%d",errno);
}

struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);

//创建epoll
int epollfd = epoll_create(1);
if(epollfd == -1){

	printf("create epoll failed!\n");
    close(fd);
	return -1;
}
struct epoll_event listenfd;
listenfd.data.fd = fd;
listenfd.events = EPOLLIN;
//设置socket(fd添加到epollfd)
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &listenfd);
if(ret == -1){
	printf("epoll_ctl epoll failed!\n");
	close(fd);
	return -1;
}
//开始用epoll来管理多个连接
	while(true){
	    epoll_event afds[256];//处理256个连接
		int num = epoll_wait(epollfd, afds, 256, 1000);//监听可读事件
		printf("epoll n=%d!\n",num);
		if(num < 0){
			printf("epoll error!\n");
			break;
		}
		else if(num == 0){
			printf("timeout!\n");
			continue;//超时
		}
		else{
		
			for(int i = 0; i < num; ++i)
			{
				if(afds[i].events == EPOLLIN)
				{
					if(afds[i].data.fd == fd)
					{  //客户端来的连接
						int afd = accept(fd, (struct sockaddr*) &clientaddr, &clientaddrlen);
						printf("accept afd= %d\n",afd);
				        if(afd == -1)
						{
							break;
			            }
				       printf("A client connected!,ip=%s,port=%d\n",inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
					   struct epoll_event tmp_fd;
						tmp_fd.data.fd = afd;
						tmp_fd.events = EPOLLIN;
						int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, afd, &tmp_fd);
						if(ret == -1)
						{
							printf("epoll_ctl epoll failed!\n");
							close(fd);
							return -1;
						}
					}
					else{
						printf("afds[%d]: fd=%d,events=%d\n",i,afds[i].data.fd,afds[i].events);
						char buf[256] = {0};
						int len = recv(afds[i].data.fd, buf, 256, 0);
					    if(len <= 0){
							printf("afd[%d] close or error\n",i);
							close(afds[i].data.fd);
						    afds[i].data.fd = -1;
						}
						printf("afd[%d] recv %d bytes:%s\n", i, len, buf);
					}
				}
			}
		}
			
	}
	close(fd);//关闭监听socket
}
	
	
	
	



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值