Fd
)的形式存在,为了使大家看得明白,我们使用一段伪代码来编写一个单线程网络服务器,以下伪代码中我们需要用程序判断当前Fdx是否有数据,这个其实过程还是有些慢的,下面让我们看一下select/poll/epoll
的原代码是怎么写的。while (1){
for(Fdx in (Fd1~Fd5)) { # Fdx 为当前遍历到的文件;Fd1~Fd5为这5个网络连接在内核中的文件描述符
if (Fdx) { # 是否有数据
# 读取Fdx并处理数据
}
}
}
# 准备文件描述符的数组 Fds
# 创建socket服务端
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd,(struct sockaddr*)&addr ,sizeof(addr));
listen (sockfd, 5);
# 创建了5个文件描述符
for (i=0;i<5;i++)
{
memset(&client, 0, sizeof (client));
addrlen = sizeof(client);
fds[i] = accept(sockfd,(struct sockaddr*)&client, &addrlen);
# 计算出一个最大的文件描述符
if(fds[i] > max)
max = fds[i];
}
# 通过以上程序我们准备好了一个文件描述符的集合假如是1 3 6 7 9 和 一个最大的文件描述符 9
while(1){
FD_ZERO(&rset);
for (i = 0; i< 5; i++ ) {
FD_SET(fds[i],&rset);
}
puts("round again");
# select参数依次含义:最大的文件描述符 + 1 (用于内核截取文件描述符); 读文件描述符集合; 写文件描述符集合;异常文件描述符集合; 超时时间;
# rset参数接受的并不是Fd集合,而是接受了FD_SET,FD_SET的类型是一个bitmap
# 假如我们文件描述符集合是 1 3 6 7 9,那么我们bitmap里面存的值就是0101001101000... (1024位01的位置坑位)。
# 无数据时select阻塞
select(max+1, &rset, NULL, NULL, NULL);
# 有数据时select会把Fd置位并返回向下执行。
for(i=0;i<5;i++) {
# 循环判断哪个Fd被置位了,然后读取数据并且处理
if (FD_ISSET(fds[i], &rset)){
memset(buffer,0,MAXBUF);
read(fds[i], buffer, MAXBUF);
puts(buffer);
}
}
}
# 声明结构图pollfd
struct pollfd {
int fd;
short events;
short revents;
};
# 构造pollfd数据
for (i=0;i<5;i++)
{
memset(&client, 0, sizeof (client));
addrlen = sizeof(client);
pollfds[i].fd = accept(sockfd,(struct sockaddr*)&client, &addrlen);
# POLLIN 读事件
pollfds[i].events = POLLIN;
}
sleep(1);
while(1){
puts("round again");
# 传入pollfds 结构体
# 5 传入的数量
# 50000 超时时间
# 也是阻塞函数
poll(pollfds, 5, 50000);
for(i=0;i<5;i++) {
if (pollfds[i].revents & POLLIN){
pollfds[i].revents = 0;
memset(buffer,0,MAXBUF);
read(pollfds[i].fd, buffer, MAXBUF);
puts(buffer);
}
}
}
# 创建一个epfd,在执行epoll_wait时需要,epfd 就相当于一种空的数据格式
struct epoll_event events[5];
int epfd = epoll_create(10);
...
...
for (i=0;i<5;i++)
{
static struct epoll_event ev;
memset(&client, 0, sizeof (client));
addrlen = sizeof(client);
ev.data.fd = accept(sockfd,(struct sockaddr*)&client, &addrlen);
ev.events = EPOLLIN;
# 对 epfd配置,相当于poll声明的结构体,定义一种数据格式,epoll_ctl相当于构造epfd这种数据格式,大概是一个文件描述符对应的一个events事件 (fd-events)
epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
}
# 准备好epfd执行下面程序
while(1){
puts("round again");
nfds = epoll_wait(epfd, events, 5, 10000);
for(i=0;i<nfds;i++) {
memset(buffer,0,MAXBUF);
read(events[i].data.fd, buffer, MAXBUF);
puts(buffer);
}
}