int poll(strucf pollfd *fds, nfds_t nfds, int timeout);
/*
fds:监听的文件描述数组
struct pollfd
{
int fd;
short events;//传入事件,取值POLLIN,POLLOUT,POLLERROR
short revents;//传出事件,传入时给0,。如果满足对应事件的话,返回非0
//POLLIN,POLLOUT,POLLERRO
}
nfds:监听数组的实际有效监听个数
timeout:超时时长,单位:毫秒(-1,阻塞等待;0,立即返回; >0:等待时长)
返回值:返回满足对应监听的文件描述符的总个数
*/
struct pollfd pfds[1024];
pfds[0].fd = lfd;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
pfds[1].fd = lfd;
pfds[1].events = POLLIN;
pfds[1].revents = 0;
pfds[2].fd = lfd;
pfds[2].events = POLLIN;
pfds[2].revents = 0;
while(1)
{
int ret = poll(pfds,5,-1);
for(i = 0; i < 5; i++)
{
if(pfds[i].revents & POLLIN)
{
accept();//如果是lfd
/***如果是cfd***/
write()/read();
}
}
}
优点:自带数组结构,可以将监听时间和返回事件集合
可以扩展监听上限(select监听上限无法修改,但是poll可以修改监听上限)
缺点:不能跨平台,只能在linux下用
无法直接定位满足监听事件文件描述符,编码难度较大
突破1024文件描述符限制:
cat /proc/sys/fs/file-max; //当前计算机所能打开的最大文件个数,受硬件影响
ulimit -a;//当前用户下的进程,默认打开文件
cat /proc/sys/fs/file-max //查看一个socket能打开的fd上限
创建红黑树:
int epoll_create(int size);//打开一个句柄,文件描述符指向一个平衡二叉树,即epfd
//size指创建红黑树的监听节点的数量。(仅供内核参考)
//返回指,指向平衡二叉树的跟节点,失败就是-1
监听红黑树:
int epollctl(int epfd, int op, int fd, struct epoll_event *event);
//用来控制红黑树
//op表示对红黑树所做的操作
// EPOLL_CTL_ADD 添加fd到监听红黑树
// EPOLL_CTL_MOD 修改fd在红黑树的监听事件
// EPOLL_CTL_DEL 摘下fd
//fd表示待监听的fd
//event: 本质上是struct epoll_event 结构体地址
// events: EPOLLIN/EPOLLOUT/EPOLLERR
// data:联合体 int fd: 对应监听事件的fd
// void *ptr: 泛型指针
// uint32_t u32;
// uint64_t u64;
//返回值: 成功0;失败 -1 eorr
阻塞红黑树:
int epoll_wait(int epfd, struct epoll_events *events, int maxevents, int timeout);
//epfd: 句柄
//events: [数组],传出参数,满足监听条件的那些fd结构体
//用epoll监听的话监听的就不止是lfd,有数组就不需要轮询所有fd时间了
//maxevents:数组中元素的总数量
//timeout:-1阻塞,0:不阻塞,>0超时时间
//返回值:
// > 0:满足监听的总个数。可以用作循环上限
// 0 :没有fd满足事件
// -1:出错
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 8192
#define SERV_PORT 8000
#define OPEN_MAX 5000
int main(int argc, char *argv[])
{
int i,lfd,cfd,sockfd;
int n,num = 0;
size_t nready,efd,res;
char buf[MAXLINE],str[INET6_ADDRSTRLEN];
socklen_t clien;
struct sockaddr_in cliaddr,servaddr;
struct epoll_event tep, ep[OPEN_MAX];//epoll_ctl para
lfd = socket(AF_INET,SOCK_STREAM,0);
int opt = 1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//port reuse
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(lfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
listen(lfd,20);
efd = epoll_create(OPEN_MAX);
tep.events = EPOLLIN; tep.data.fd = lfd;
res = epoll_ctl(efd,EPOLL_CTL_ADD,lfd,&tep);
for(;;)
{
nready = epoll_wait(efd,ep,OPEN_MAX,-1);
for(i = 0; i < nready; i++)
{
if(!(ep[i].events & EPOLLIN))
continue;
if(ep[i].data.fd == lfd)
{
clien = sizeof(cliaddr);
cfd = accept(lfd,(struct sockaddr *)&cliaddr, &clien);
tep.events = EPOLLIN;
tep.data.fd = cfd;
res = epoll_ctl(efd,EPOLL_CTL_ADD,cfd,&tep);
}
else
{
sockfd = ep[i].data.fd;
n = read(sockfd,buf,MAXLINE);
if(n <= 0)
{
res = epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);
close(sockfd);
}
else
{
for(i = 0; i < n; i++)
{
buf[i] = toupper(buf[i]);
}
write(STDOUT_FILENO,buf,n);
write(sockfd,buf,n);
}
}
}
}
close(lfd);
return 0;
}