select/poll/epoll区别?
select:
1、select监听的最大文件描述符是1024个;
2、select需要反复构造表,反复从用户空间向内核空间拷贝表,效率低
3、当数据准备好后,select需要再次遍历表,找出准备好的文件描述符,效率低
poll:
1、poll监听的文件描述符没有限制
2、poll不需要反复构造表,不需要反复拷贝表,效率高
3、当数据准备好之后,poll需要遍历表,找出准备好的文件描述符,效率低
epoll:
1、epoll监听的文件描述符没有限制
2、epoll不需要反复构造表,不需要反复拷贝表,效率高
3、当数据准备好之后,epoll直接能够找出准备好的文件描述符,不需要遍历表,效率高。
#include "c.h"
#define ERR_MSG(msg) \
do \
{ \
fprintf(stderr, "line:%d", __LINE__); \
perror(msg); \
} while (0)
#define IP "192.168.250.100"
#define PORT 6666
#define BUFLEN 128
int deal_cli_msg(int newfd, struct sockaddr_in cin);
// 回收僵尸进程
void handler(int sig)
{
while (waitpid(-1, NULL, WNOHANG) > 0)
;
}
int main(int argc, const char *argv[])
{
char buf[BUFLEN];
// 捕获17号 SIGCHLD信号,回收僵尸进程
__sighandler_t s = signal(17, handler);
if (SIG_ERR == s)
{
ERR_MSG("signal");
return -1;
}
// 创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
{
ERR_MSG("socket");
return -1;
}
printf("sfd=%d\n", sfd);
// 允许端口快速重用
int reuse = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速重用成功\n");
// 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
// 将ip和端口绑定到套接字上
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
ERR_MSG("bind");
return -1;
}
printf("ip绑定套接字成功__%d__\n", __LINE__);
// 将套接字设置为可监听状态
if (listen(sfd, 128) < 0)
{
ERR_MSG("listen");
return -1;
}
printf("将套接字设置为可监听状态成功__%d__\n", __LINE__);
// 存储连接成功的客户端地址信息
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
int newfd = -1;
int epfd,epct,i,ret;
struct epoll_event event; //定义epoll 事件
struct epoll_event events[20]; //定义epoll 事件集合
epfd = epoll_create(1); // 创建epoll 的fd //红黑树根节点
event.data.fd = sfd; //填充事件的fd
event.events = EPOLLIN | EPOLLET; //填充 事件类型
epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event); //把serverFd(监听FD)注册到epfd中
while(1){
epct = epoll_wait(epfd,events,20,-1); // 等待事件到来,阻塞模式
for(i=0;i<epct;i++){ //根据epoll返回的值来查询事件
if(events[i].data.fd == sfd){ // 如果事件的fd是监听fd,调用accept处理
newfd = accept(events[i].data.fd,(struct sockaddr *)&cin,&addrlen);
event.data.fd = newfd;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,newfd,&event);
}
else { //如果不是serverFd,应是client数据事件,调用读数据
memset(buf,0,BUFLEN);
ret = read(events[i].data.fd,buf,BUFLEN);
if(ret <=0){ //客户端断开
printf("connect disconnected\n");
close(events[i].data.fd); //关闭文件描述符
epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,&event); //删除监听的客户端fd
continue;
}
}
}
}
// 关闭进程的所有的文件描述符
for (i = 0; i < getdtablesize(); i++)
{
close(i);
}
return 0;
}