socket描述符
在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系很大
epoll_create
int epoll_create(int size);
创建一个epoll的句柄。size为epoll所支持的最大句柄数
epoll_wait
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
events:储存所有的读写事件
maxevents:最大事件数量
epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
epoll_ctl用来添加/修改/删除需要侦听的文件描述符及其事件。任何被侦听的文件符只要被关闭,那么它也会自动从被侦听的文件描述符集合中删除;要尽量少地调用epoll_ctl,防止其引来的开销
EPOLL_CTL_ADD:添加
EPOLL_CTL_MOD:修改
EPOLL_CTL_DEL:删除
举例
int epfd = epoll_create(10);
if(epfd < 0)
{
perror("epoll_create");
return epfd;
}
struct epoll_event ev = {0};
struct epoll_event events[10] = {0};
ev.data.fd = sockfd;
ev.events = EPOLLIN|EPOLLET;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
if(ret < 0)
{
perror("epoll_ctl");
return ret;
}
for(;;)
{
int epfds = epoll_wait(epfd, events, 10, 500);
if(epfds < 0)
{
perror("epoll_wait");
return epfds;
}
int i = 0;
for(i = 0; i < epfds; i++)
{
if(events[i].data.fd == sockfd)
{
struct sockaddr_in ss;
socklen_t len = sizeof ss;
int afd = accept(sockfd, (struct sockaddr*)&ss, &len);
if(afd < 0)
{
perror("accept");
return afd;
}
printf("接受到新连接 %d\n", afd);
ev.data.fd = afd;
ev.events = EPOLLIN|EPOLLET;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, afd, &ev);
if(ret < 0)
{
perror("epoll_ctl");
return ret;
}
}
else if(events[i].events & EPOLLIN)
{
char buf[100] = {0};
memset(buf, 0, sizeof(buf));
int r = recv(events[i].data.fd, buf, sizeof(buf), 0);
if(r > 0)
{
printf("接收到数据 [%d]: %s\n", events[i].data.fd, buf);
}
}
}
}
实验现象
# ./a.out
接受到新连接 5
接收到数据 [5]: hello