epoll简介 :
用于支持高并发的事件机制
优点 :
1、支持打开一个很大个数的socket连接数(linux socket连接默认是2048),
最大可以达到最大文件数目( cat /proc/sys/fs/file-max, 大小和系统内存相关)
ps : apache使用的就是多进程方式(一个进程最大支持2048 socket连接,通过增多进程来实现)
2、IO效率不随FD的增多而降低
select/poll会随着socket集合的增大而变慢,因为每次调用都会线性扫描全部的集合,效率呈线性下降
epoll只扫描活跃的soket,根据每个fd上的callback回调
3、使用mmap加速内核和用户空间的消息传递
4、内核微调
触发方式 :
1、边缘触发
2、水平触发
相关函数使用 :
是创建size大小的文件描述符
epoll_create(int size);
等待事件的发生
epoll_wait(int epollfd,struct epoll_event *events,int maxevent,int timeout);
用来向内核注册,删除,修改一个文件描述符的
epoll_ctl(int epollfd,int op,struct epoll_event *events);
例子 :
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#define INFTIM 1000
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock, F_GETFL);
if(opts < 0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts | O_NONBLOCK;
if(fcntl(sock, F_SETFL, opts) < 0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
int main()
{
int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
ssize_t n;
char line[MAXLINE];
socklen_t clilen;
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
struct epoll_event ev, events[20];
//生成用于处理accept的epoll专用的文件描述符
epfd = epoll_create(256);
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
//把socket设置为非阻塞方式
setnonblocking(listenfd);
//设置与要处理的事件相关的文件描述符
ev.data.fd = listenfd;
//设置要处理的事件类型
ev.events = EPOLLIN | EPOLLET;
//注册epoll事件
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
char *local_addr = "200.200.200.204";
inet_aton(local_addr, &(serveraddr.sin_addr)); //htons(SERV_PORT);
serveraddr.sin_port = htons(SERV_PORT);
bind(listenfd, (sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, LISTENQ);
maxi = 0;
for ( ; ; )
{
//等待epoll事件的发生
nfds = epoll_wait(epfd, events, 20, 500);
//处理所发生的所有事件
for(i = 0; i < nfds; ++i)
{
if(events[i].data.fd == listenfd)
{
connfd = accept(listenfd, (sockaddr *)&clientaddr, &clilen);
if(connfd < 0)
{
perror("connfd<0");
exit(1);
}
setnonblocking(connfd);
char *str = inet_ntoa(clientaddr.sin_addr);
std::cout << "connect from " < _u115 ? tr << std::endl;
//设置用于读操作的文件描述符
ev.data.fd = connfd;
//设置用于注测的读操作事件
ev.events = EPOLLIN | EPOLLET;
//注册ev
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if(events[i].events & EPOLLIN)
{
if ( (sockfd = events[i].data.fd) < 0) continue;
if ( (n = read(sockfd, line, MAXLINE)) < 0)
{
if (errno == ECONNRESET)
{
close(sockfd);
events[i].data.fd = -1;
}
else
std::cout << "readline error" << std::endl;
}
else if (n == 0)
{
close(sockfd);
events[i].data.fd = -1;
}
//设置用于写操作的文件描述符
ev.data.fd = sockfd;
//设置用于注测的写操作事件
ev.events = EPOLLOUT | EPOLLET;
//修改sockfd上要处理的事件为EPOLLOUT
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
else if(events[i].events & EPOLLOUT)
{
sockfd = events[i].data.fd;
write(sockfd, line, n);
//设置用于读操作的文件描述符
ev.data.fd = sockfd;
//设置用于注测的读操作事件
ev.events = EPOLLIN | EPOLLET;
//修改sockfd上要处理的事件为EPOLIN
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
}
本文介绍epoll机制的优势,包括支持大量socket连接、高效处理IO、使用mmap加速数据传递等,并提供了一个简单的C++示例代码,展示了如何使用epoll进行网络编程。
443

被折叠的 条评论
为什么被折叠?



