概念
select和epoll都归属于IO多路复用是一种代替多线程实现服务器并发的方案。举个例子,假设小明要来8公寓找小果,但是不知道他在哪个寝室,但是每个寝室都分配了一个女仆阿姨,小果的阿姨一眼看到了小明,就把他叫到小果那里了;过了一阵子学校没钱了,只雇佣了一个阿姨,小明找不到小果,阿姨就挨个屋子问小果在哪里直到找到小果或者查无此人来错公寓嘞您;又过了一阵子,学校管理升级阿姨直接用花名册就能找到每个同学的宿舍。OK多线程select和epoll正好对应这三种情况,多线程就是为所有链接的套接字安排一个线程负责信息的收发;select基于轮询的思想,对所有需要判断的套接字分别询问是否需要响应;epoll可以直接返回一个数组,其中保存的就是所有需要响应的套接字,不需要像select那样做多余的访问过程。
select
set<int> fd;//加入需要监听的套接字
timeval timeout = {0};
timeout.tv_usec = usec;
FD_ZERO(&fds);
int maxfd = 0;
for(int i:fd){
maxfd = maxfd>i?maxfd:i;
FD_SET(i,&fds);
}
switch(select(maxfd+1,&fds,NULL,NULL,&timeout)){
case -1:{
cout<<"select error";
exit(1);
}case 0:break;
default:{
for(int i:fd){
if(FD_ISSET(i,&fds)){
//处理套接字i的过程
}
}
}
}
epoll
void listen_loop(unsigned int sock_fd)
{
int epollfd, i, ret;
int timeout = 300;
struct epoll_event event;
struct epoll_event eventList[10];
/*创建epoll监听事件*/
epollfd = epoll_create(10);
event.events = EPOLLIN | EPOLLET;
event.data.fd = sock_fd;
/*注册epoll监听事件.*/
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &event) < 0) {
printf("register epoll event err !");
return;
}
while (1) {
//ret为个数
ret = epoll_wait(epollfd, eventList, 10, timeout);
/*epoll事件错误.*/
if (ret < 0) {
printf("epoll event err!");
break;
}
/*无事件返回.*/
else if (ret == 0) {
continue;
}
/*epoll返回事件.*/
for (i = 0; i < ret; i++) {
/*epoll 错误*/
if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN)) {
//错误
exit(1);
}
//half connection
if (eventList[i].events & EPOLLRDHUP) {
//客户端关闭socket
close(eventList[i].data.fd);
}
/*accept事件*/
if (eventList[i].data.fd == sock_fd) {
//等于服务器socket 处理连接
}
/*非sock_fd则为其他事件.*/
else {
//否则为client的socket接受信息
}
}
}
close(epollfd);
close(sock_fd);
return;
}
本文对比分析了select和epoll两种IO多路复用技术在服务器并发处理中的作用与实现方式。select通过轮询机制监测多个套接字的状态,而epoll则能更高效地返回所有需要响应的套接字,避免了不必要的访问,适用于高并发场景。
395

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



