您的位置:首页 > 运维架构 > Linux

Linux epoll服务器、epoll、poll、select优缺点

2017-06-29 17:40 369 查看

epoll、poll和select优缺点

select

优点

(1)select()的可移植性更好,在某些Unix系统上不支持poll()

(2)select() 对于超时值提供了更好的精度:微秒,而poll是毫秒

缺点

(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

(3)select支持的文件描述符数量太小了,默认是1024

poll

优点

(1)poll() 不要求开发者计算最大文件描述符加一的大小。

(2)poll() 在应付大数目的文件描述符的时候相比于select速度更快

(3)它没有最大连接数的限制,原因是它是基于链表来存储的。

缺点

(1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。

(2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符

epoll

epoll底层实现

在调用epoll_create时操作系统会创建一颗红黑树存放socket和一个队列存放就绪事件

优点

(1)支持一个进程打开大数目的socket描述符(FD)

(2)IO效率不随FD数目增加而线性下降

(3)使用mmap加速内核与用户空间的消息传递。

epoll服务器实现

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

#define MAX_EPOLL_EVENTS 64

static void usage(char* arg)
{
printf("Usage:%s [local_ip][local_port]\n",arg);
}

int starup(const char* ip,int port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
exit(2);
}

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip);
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

if(bind(sock,(struct sockaddr*)&server,sizeof(server)) < 0)
{
perror("bind");
exit(3);
}

if(listen(sock,5) < 0)
{
perror("listen");
exit(4);
}

return sock;
}

int main(int argc,char* argv[])
{
if(3 != argc)
{
usage(argv[0]);
return 1;
}

int listen_sock = starup(argv[1],atoi(argv[2]));
int epfd = epoll_create(200);
if(epfd < 0)
{
perror("epoll_create");
return 5;
}

struct epoll_event ev,ev_array[MAX_EPOLL_EVENTS];
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev) != 0)
{
perror("epoll_ctl");
return 6;
}

while(1)
{
int num = epoll_wait(epfd,ev_array,MAX_EPOLL_EVENTS,10000);
switch(num)
{
case -1:
{
perror("epoll_wait");
return 7;
break;
}
case 0:
{
printf("nothing ready...\n");
break;
}
default:
{
int i;
for(i = 0;i < num; ++i)
{
if(ev_array[i].data.fd == listen_sock && ev_array[i].events & EPOLLIN)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock < 0)
{
perror("accept");
continue;
}

printf("get a new client:%s,%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
struct epoll_event event;
event.events = EPOLLIN | EPOLLOUT;
event.data.fd = new_sock;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,new_sock,&event) != 0)
{
perror("epoll_ctl");
close(new_sock);
continue;
}
}
else if(ev_array[i].events & E
4000
POLLIN)
{
char buf[1024];
ssize_t s = read(ev_array[i].data.fd,buf,sizeof(buf)-1);
if(s<0)
{
perror("read:EPOLLIN");
if(epoll_ctl(epfd,EPOLL_CTL_DEL,ev_array[i].data.fd,&ev_array[i])!=0)
{
perror("epoll_ctl");
continue;
}
close(ev_array[i].data.fd);
continue;
}
else if(s == 0)
{
printf("client quit...\n");
epoll_ctl(epfd,EPOLL_CTL_DEL,ev_array[i].data.fd,&ev_array[i]);
close(ev_array[i].data.fd);
continue;
}
else
{
buf[s]=0;
printf("%s\n",buf);
}
}
else if(ev_array[i].events & EPOLLOUT)
{
char* buf = "hello word";
write(ev_array[i].data.fd,buf,strlen(buf));
epoll_ctl(epfd,EPOLL_CTL_DEL,ev_array[i].data.fd,&ev_array[i]);
close(ev_array[i].data.fd);
printf("client is quited\n");
continue;
}
}//for
}
}//switch
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: