java怎么自动生成uml图(编程之美IO多路复用)
java怎么自动生成uml图(编程之美IO多路复用)另外,在客户端众多的情况下,无论是select还是poll函数在执行一段时间后效率都是直线下降的,因为实际中处于就绪状态的客户端毕竟是少数。前面刚说了没有绝对完美的东西,poll也存在着几个比较影响人心情的问题:poll函数相比select函数有个质的飞跃——对文件描述符的个数不在限制,虽然没有解决开销大的问题,不过十全十美的东西确实也不存在对吧,这个道理放在程序开发上也是如此。poll函数和select函数没有本质上的区别。poll将用户传入的数组拷贝到内核,通过查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,就把当前进程挂起,直到设备就绪或者超时,被唤醒后重新对fd进行新的遍历。至于poll为什么没有了对文件描述符个数的限制,是因为在该函数使用链表作为存储结构,链表的特性就是可以充分使用系统空间,非常灵活。对链表感兴趣
各位看官大家好,在上一篇文章中,我们详细讲解了select函数,也在文末上传了实现代码。今天我们来了解一下Poll函数,他和select又有哪些不同,哪些相似。
很尴尬我找不到合适的配图
Poll函数详解在上一篇文章中我们提到select有如下几个缺点:
- select函数能打开的文件描述符(fd)有限;
- select采用轮询的遍历方式,导致效率较低;
- 由于执行此函数需要一个非常大的struct(结构体)来存储文件描述符属性,会占用很多的系统资源
要知道这些问题是select设计伊始就已经存在的,只要使用就势必存在上述的缺点。
poll函数相比select函数有个质的飞跃——对文件描述符的个数不在限制,虽然没有解决开销大的问题,不过十全十美的东西确实也不存在对吧,这个道理放在程序开发上也是如此。
poll函数和select函数没有本质上的区别。poll将用户传入的数组拷贝到内核,通过查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,就把当前进程挂起,直到设备就绪或者超时,被唤醒后重新对fd进行新的遍历。
至于poll为什么没有了对文件描述符个数的限制,是因为在该函数使用链表作为存储结构,链表的特性就是可以充分使用系统空间,非常灵活。对链表感兴趣的朋友可以百度相关内容,资源非常多,这里不再累述。
前面刚说了没有绝对完美的东西,poll也存在着几个比较影响人心情的问题:
- 由于一直进行遍历,必定会出现无用重复的循环,且无法避免;
- fd的数组整体复制在用户态和内核地址空间中,但这些fd不一定会用到,也就是说这些复制操作不一定有意义。
- 如果对收到的fd信息没有处理,那么下次执行的时会再次报告该fd,执行多少次就报告多少次(看起来poll函数确实记性不好。)
另外,在客户端众多的情况下,无论是select还是poll函数在执行一段时间后效率都是直线下降的,因为实际中处于就绪状态的客户端毕竟是少数。
下面我们来具体学习一下poll函数的原型及参数含义:
int poll(struct pollfd fd[] nfds_t nfds int timeout);
struct pollfd fd【】: 一个结构数组 struct pollfd结构如下:
struct pollfd{
int fd; //文件描述符
short events; //请求事件
short revents; //返回事件
};
nfds_t nfds:监听描述符的个数
int timeout:阻塞时间单位:ms
这里要注意一下poll函数的返回值,有以下三种情况:
- >0:数组fd中准备好读、写或出错状态的那些socket描述符的总数量;
- =0:数组fd中所有socket描述符准备好读、写,或出错;
- -1:poll调用错误,全局变量为error。
下面是具体的实现代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
int main()
{
int fd = open("/dev/input/mouse1" O_RDONLY);//初始化文件描述符
if (fd < 0)
{
perror("open");
return -1;
}
printf("open success\n");
struct pollfd fds[2];
fds[0].fd = 0; //把键盘加入集合中
fds[0].events = POLLIN;
fds[1].fd = fd; //把鼠标加入集合中
fds[1].events = POLLIN;
int retval;
char buf[100];
while (1)
{
retval = poll(fds 2 1000);
if (retval < 0)
{
perror("poll");
break;
}
else if (0 == retval)
{
printf("timeout..............\n");
continue;
}
if (fds[0].revents & POLLIN) //判断是否是键盘产生事件
{
read(0 buf sizeof(buf));
printf("Data from keyboard!\n");
}
if (fds[1].revents & POLLIN)
{
read(fd buf sizeof(buf));
printf("Date from Mouse!\n");
}
}
close(fd);
return 0;
}
鉴于之前有朋友反应服务器代码太长,所以这里我放了一篇对输入设备事件处理的C代码,涉及到了一点文件IO的知识,不过很简单,代码中也有备注。对本篇内容有疑惑的看官欢迎留言或者私信,看到了都会回复,最后谢谢您的收看!