select
是一种系统调用,用于监视多个文件描述符的状态。int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select的缺点
poll的基本概念
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
epoll的基本概念
epoll_create
创建一个epoll实例。epoll_ctl
用于添加、修改或删除文件描述符。epoll_wait
用于等待事件的发生。epoll的优点
1.描述符上限:select 的文件描述符数量通常有限制(一般为1024),而 poll 和 epoll 对文件描述符的数量没有限制。
2.数据结构传递方式:select 在每次调用时需要将所有注册的文件描述符集合复制到内核中;poll 则使用一个 pollfd 数组来传递数据,仍需在每次调用时进行复制;相比之下,epoll 维护内核中的红黑树和双向链表,仅在有事件发生时进行处理,避免了不必要的复制。
3.性能开销:select 因为需要多次进行内核态切换,表现出较高的性能开销;poll 的性能开销稍微较低,但仍需切换用户态与内核态;而 epoll 的开销最低,仅在事件发生时切换,能显著减少不必要的性能损耗。
3.时间复杂度:在 select 和 poll 中,处理的复杂度都是 O(n),需要遍历所有注册的文件描述符;而在 epoll 中,复杂度则降低为 O(K),仅需要遍历就绪事件的数量,提升了效率。 适用场景:select 和 poll 适合处理较少的文件描述符,而 epoll 更适合处理大量并发连接,能够提供更好的性能。
4.支持边缘触发:epoll 支持边缘触发模式,而 select 和 poll 则不支持这种机制。
5.返回就绪事件的数量:poll 返回就绪的文件描述符数量,epoll 通过回调机制或事件循环返回就绪事件,相比之下更灵活高效。
#include
#include
#include
#include
#include
#include
#include
#include
#include /* superset of previous */
#include
#include
#include
int init_tcp_ser(const char *ip ,unsigned short port)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("fail socket");
return -1;
}
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
if (-1 == ret)
{
perror("fail bind");
return -1;
}
ret = listen(sockfd, 128);
if (-1 == ret)
{
perror("fail listen");
return -1;
}
return sockfd;
}
int epoll_add_fd(int epfds,int fd,uint32_t event)
{
struct epoll_event ev;
ev.events = event;
ev.data.fd = fd;
int ret = epoll_ctl(epfds,EPOLL_CTL_ADD,fd,&ev);
if(-1 == ret )
{
perror("epoll create fail");
return -1;
}
return 0;
}
int epoll_del_fd(int epfds,int fd)
{
int ret = epoll_ctl(epfds,EPOLL_CTL_DEL,fd,NULL);
if(-1 == ret )
{
perror("del fail");
return -1;
}
return 0;
}
int main(int argc , char *argv[])
{
char buf[1024] = {0};
int listenfd = init_tcp_ser("192.168.1.167",50000);
struct epoll_event evs[1024];
int epfds = epoll_create(1024);
epoll_add_fd(epfds,listenfd,EPOLLIN);
while(1)
{
int cnt = epoll_wait(epfds,evs,1024,-1);
if(cnt < 0)
{
perror("epoll wait fail");
return -1;
}
for(int i = 0; i < cnt ;++i)
{
if (listenfd == evs[i].data.fd)
{
int connfd = accept(listenfd,NULL,NULL);
epoll_add_fd(epfds,connfd,EPOLLIN);
}
else
{
memset(buf,0,sizeof(buf));
size_t size = recv(evs[i].data.fd,buf,sizeof(buf),0);
if(size <= 0)
{
epoll_del_fd(epfds,evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
printf("cli---> %s\n", buf);
strcat(buf, "------ok!");
size = send(evs[i].data.fd, buf, strlen(buf), 0);
}
}
}
return 0;
}