进入2.6内核时代, select应该进垃圾堆了
高并发服务器用select效率极低, 特别是使用非阻塞IO时更是慢得一蹋糊涂
改用epoll会大大改善
我一个程序监听从8000到18000共计1万个端口, 启动1万个LISTEN
用epoll来阻塞, 系统非常轻松, 完全没有惊群现象
epoll用法比select简单
初始化:创建epoll描述字; 向epoll描述字添加需要响应的套接字, 初始化过程只要一次即可
使用: 等待epoll事件发生, 提取事件的套接字进行相应的读写操作
static int s_epfd;//epoll描述字
{//初始化epoll
struct epoll_event ev;
//设置epoll
s_epfd = epoll_create(65535);
{//这个过程可以循环以便加入多个LISTEN套接字进入epoll事件集合
//服务器监听创建
rc = listen();//listen参数这里省略
//加入epoll事件集合
ev.events = EPOLLIN;
ev.data.fd = rc;
if (epoll_ctl(s_epfd, EPOLL_CTL_ADD, rc, &ev) < 0) { bitsCN~com
fprintf(stderr, "epoll set insertion error: fd=%d", rc);
return(-1);
}
}
}
{//epoll事件处理
int i, nfds, sock_new;
struct epoll_event events[16384];
for( ; ; ) {
//等待epoll事件
nfds = epoll_wait(s_epfd, events, 16384, -1);
//处理epoll事件
for(i = 0; i < nfds; i++) {
//events.data.fd是epoll事件中弹出的套接字
//接收连接
sock_new = accept(events.data.fd);//accept其它参数这里省略了
if(0 > sock_new) {
fprintf(stderr, "接收客户端连接失败/n");
continue;
}
}
}
}
1、为什么select是落后的?
首先,在Linux内核中,select所用到的FD_SET是有限的,即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数,在我用的2.6.15-25-386内核中,该值是1024,搜索内核源代码得到:
include/linux/posix_types.h:#define __FD_SETSIZE 1024
也就是说,如果想要同时检测1025个句柄的可读状态是不可能用select实现的。或者同时检测1025个句柄的可写状态也是不可能的。
其次,内核中实现select是用轮询方法,即每次检测都会遍历所有FD_SET中的句柄,显然,select函数执行时间与FD_SET中的句柄个数有一个比例关系,即select要检测的句柄数越多就会越费时。
当然,在前文中我并没有提及poll方法,事实上用select的朋友一定也试过poll,我个人觉得select和poll大同小异,个人偏好于用select而已。