本节通过实例代码运行结果,让大家看到在并发式IO访问时非阻塞IO遭遇的困境,由此引入非阻塞式IO。
3.6.2.1、程序中读取键盘
include <stdio.h>
include <unistd.h>
include <string.h>
int main(void)
{
// 读取键盘
// 键盘就是标准输入,stdin
char buf[100];
memset(buf, 0, sizeof(buf));
printf("before read.
");
read(0, buf, 5);
printf("读出的内容是:[%s].
", buf);
return 0;
}
运行过程:
./a.out
before read.
进程被阻塞住,因为此时还没有键盘输入,此时,键入一个a,
before read.
a
打印一个a,然后键入bcdggggg,
before read.
abcdggggg
因为linux使用行缓存技术。如果在结束,则按一个Enter就可以结束这个函数。(行缓存for直到换行符到了)。
3.6.2.2、程序中读取鼠标
键盘是一个标准输入设备,所以可以直接打开。但是鼠标不是标准输入设备,所以要先用open打开鼠标鼠标。
ls /dev/input
by-id by-path event0 event1 event2 event3 mice mouse0 mouse1
cat /dev/input/mouse1
如何判断哪个是我们的鼠标,只要cat /dev/input/mouse1,就会阻塞,然后移动鼠标,如果有打印出来的东西,就是当前鼠标设备。
include <stdio.h>
include <unistd.h>
include <string.h>
include <sys/types.h>
include <sys/stat.h>
include <fcntl.h>
int main(void)
{
// 读取鼠标
int fd = -1;
char buf[200];
fd = open("/dev/input/mouse1", O_RDONLY);
if (fd < 0)
{
perror("open:");
return -1;
}
memset(buf, 0, sizeof(buf));
printf("before 鼠标 read.
");
read(fd, buf, 50);
printf("鼠标读出的内容是:[%s].
", buf);
return 0;
}
结果分析:先前打印before 鼠标 read.阻塞住,直到鼠标移动,才打印出乱码[(�]。打印出乱码的原因是鼠标移动输入二进制,但是终端以ASCII方式解析。
3.6.2.3、程序中同时读取键盘和鼠标(有问题没想明白)
include <stdio.h>
include <unistd.h>
include <string.h>
include <sys/types.h>
include <sys/stat.h>
include <fcntl.h>
int main(void)
{
// 读取鼠标
int fd = -1;
char buf[200];
fd = open("/dev/input/mouse1", O_RDONLY);
if (fd < 0)
{
perror("open:");
return -1;
}
memset(buf, 0, sizeof(buf));
printf("before 鼠标 read.
");
read(fd, buf, 50);
printf("鼠标读出的内容是:[%s].
", buf);
// 读键盘
memset(buf, 0, sizeof(buf));
printf("before 键盘 read.
");
read(0, buf, 5);
printf("键盘读出的内容是:[%s].
", buf);
return 0;
}
3.6.2.4、问题分析
总结:阻塞式IO:函数调用会被阻塞。本质是当前进程调用了函数,进入内核里面去后,因为当前进程的执行条件不满足,内核无法里面完成操作,就挂起这个进程,去执行其他进程。默认使用阻塞IO。是linux系统的常态。但是阻塞式IO有一个缺点,比如说如果要同时读取鼠标和键盘的输入(不知道鼠标动还是键盘动),就会遇见很糟糕的情况,这时我们可以用并发式IO解决,有三种方法可以实现:非阻塞IO,多路复用IO,异步IO。
并发式IO可以解决这个问题