1. 题目
笔者出题:分别使用select, poll, epoll实现回显程序
2. 代码展示
2.1:select
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <sys/select.h>
#define MAX 20
void set_fl(int fd, int flags)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
errx(1,"fcntl F_GETFL error");
val |= flags;
if (fcntl(fd, F_SETFL, val) < 0)
errx(1,"fcntl F_SETFL error");
}
int main(void)
{
int n;
char buf[MAX];
fd_set r_set;
FD_ZERO(&r_set);
FD_SET(STDIN_FILENO,&r_set);
set_fl(STDIN_FILENO, O_NONBLOCK);
set_fl(STDOUT_FILENO, O_NONBLOCK);
while(select(1,&r_set,NULL,NULL,NULL) != -1)
if(fgets(buf,MAX,stdin) != NULL)
{
if(fputs(buf,stdout) == EOF)
errx(1,"error in write\n");
//FD_SET(STDIN_FILENO,&r_set); 这里要不要这句都可以,因为如果select返回必然,r_set中STDIN_FILENO置位,下次调用select的时候也不会有任何问题。
}
else
errx(1,"end of file\n");
exit(0);
}
结果如下:
[root@localhost ~]# ./14_2
aaa
aaa
ssss
ssss
14_2: end of file//键入crtl+d
[root@localhost ~]#
首先fgets
和fputs
函数此时为非阻塞,因为这里很明显只设置了一个fd
,所以select
函数返回值不为-1
时,直接调用fgets
读取。结果显示很好的完成了任务,要重申下**select
此时为同步阻塞,fgets
此时是否阻塞都不重要了!**
2.2:poll
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <poll.h>
#define MAX 20
void set_fl(int fd, int flags)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
errx(1,"fcntl F_GETFL error");
val |= flags;
if (fcntl(fd, F_SETFL, val) < 0)
errx(1,"fcntl F_SETFL error");
}
int main(void)
{
int n;
char buf[MAX];
struct pollfd fdarray;
fdarray.fd=STDIN_FILENO;
fdarray.events=POLLIN;
fdarray.revents=0;
set_fl(STDIN_FILENO, O_NONBLOCK);
set_fl(STDOUT_FILENO, O_NONBLOCK);
while(poll(&fdarray,1,-1) != -1)
if(fgets(buf,MAX,stdin) != NULL)
{
if(fputs(buf,stdout) == EOF)
errx(1,"error in write\n");
}
else
errx(1,"end of file\n");
exit(0);
}
结果如下:
[root@localhost ~]# ./14_3
aaa
aaa
ddddd
ddddd
14_3: end of file
[root@localhost ~]#
NOTE : 大体上和上述一样,不赘述。
2.3:epoll
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <sys/epoll.h>
#define MAX 20
void set_fl(int fd, int flags)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
errx(1,"fcntl F_GETFL error");
val |= flags;
if (fcntl(fd, F_SETFL, val) < 0)
errx(1,"fcntl F_SETFL error");
}
int main(void)
{
int n;
char buf[MAX];
int efd,m;
struct epoll_event even,events[2];
even.events=EPOLLIN|EPOLLOUT;
even.data.fd=STDIN_FILENO;
set_fl(STDOUT_FILENO, O_NONBLOCK);
set_fl(STDIN_FILENO, O_NONBLOCK);
if((efd=epoll_create(2)) == -1)
errx(1,"error in epoll_create\n");
if(epoll_ctl(efd,EPOLL_CTL_ADD,STDIN_FILENO,&even) == -1)
errx(1,"error in epoll_ctl\n");
while((m=epoll_wait(efd,events,2,-1)) != -1)
for(int i=0;i<m;i++)
if(events[i].events & EPOLLIN == EPOLLIN)
if(events[i].data.fd == STDIN_FILENO)
if(fgets(buf,MAX,stdin) != NULL)
{
if(fputs(buf,stdout) == EOF)
errx(1,"error in write\n");
}
else
errx(1,"end of file\n");
exit(0);
}
结果如下:
[root@localhost ~]# ./14_4
asd
asd
fssss
fssss
14_4: end of file
[root@localhost ~]#
epoll_create
参数随便设,大于0即可,虽然笔者这里只设置了一个fd
,但是还是把events
数组设置成2
,目的是为了epoll_wait
之后体现下由编程人员进行轮询查询的特点。结果也是很好的完成了任务 。_
3. 总结
无论使用哪个函数,其都是同步模型。也就是说编程者还必须对结果进行一定的处理。**换种说法:同步的含义代表我们效果上还是阻塞在read或者write操作上。如果将read或者write的操作投入队列中,那就是异步的方式完成了IO操作。但是不代表整体代码模型使用的是异步模型,有点绕。**而函数自身是否阻塞,也许在某些要求实时性的场合,可以改善程序效率。笔者在最后epoll
刻意体现了其使用大体框架。这些函数真正的用武之地当然不是为了回显程序这么简单的要求,等笔者学到socket
之后再仔细考虑这些内容吧。