Linux中的文件备用来完成大量任务:
- 正常的文件中保持久的数据
- 通过套接字进行网络通讯
- 通过设备文件来访问设备
,,,
多路输入输出
阻塞I/O
首先创建两个管道,命名p1和p2(使用mknod命令), 然后在两个终端分别运行cat > p1和 cat > p2。在第三个终端上运行程序mpx-blocks。
运行结果是在每个cat窗口键入文字输入,程序的表现是,在每一行输入结束前,两个cat窗口中的命令是不会把任何数据写到管道中的。
/* mpx-blocks.c - Displays input from two pipes, alternatively */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int fds[2];
char buf[4096];
int i;
int fd;
if ((fds[0] = open("p1", O_RDONLY)) < 0) {
perror("open p1");
return 1;
}
if ((fds[1] = open("p2", O_RDONLY)) < 0) {
perror("open p2");
return 1;
}
fd = 0;
while (1) {
/* if data is available read it and display it */
i = read(fds[fd], buf, sizeof(buf) - 1);
if (i < 0) {
perror("read");
return 1;
} else if (!i) {
printf("pipe closed\n");
return 0;
}
buf[i] = '\0';
printf("read: %s", buf);
/* read from the other file descriptor */
fd = (fd + 1) % 2;
}
}
上述程序同一时刻只能从一个管道中读取数据,同时从一个管道中读取数据的时候一直被阻塞住另一个管道文件被忽略,直到该文件中有了数据read之后并返回,这个方法表现出来的行为读取数据并不是很流畅的数据多路传输。
非阻塞I/O
通过系统调用fcntl()可以来指定一个文件是非阻塞的。当一个文件是非阻塞的时候,read总是可以立即返回,如果没有现成的数据,仅仅简单地返回一个0。非阻塞I/O通过避免文件上的操作阻塞而为多路传输提供了一个简单的方法。
基于上面的程序进行修改:
/* mpx-nonblock.c - Displays input from two pipes via nonblocking I/O */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int fds[2];
char buf[4096];
int i;
int fd;
/* open both pipes in nonblocking mode */
if ((fds[0] = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
perror("open p1");
return 1;
}
if ((fds[1] = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
perror("open p2");
return 1;
}
fd = 0;
while (1) {
/* if data is available read it and display it */
i = read(fds[fd], buf, sizeof(buf) - 1);
if ((i < 0) && (errno != EAGAIN)) {
perror("read");
return 1;
} else if (i > 0) {
buf[i] = '\0';
printf("read: %s", buf);
}
/* read from the other file descriptor */
fd = (fd + 1) % 2;
}
}
阻塞和非阻塞之间的区别在于,非阻塞的时候它读取的管道关闭时候它并不退出。从没有任何写入者的管道读取数据的时候非阻塞read会返回0个字节数;从一个有写入者但没有数据管道读取数据的时候read返回EAGAIN。
缺点:虽然非阻塞的I/O很容易地在文件描述符之间切换,也付出了很大的系统消耗代价,程序不停地在运行,永远不会阻塞,不断地轮询哪个文件可以读取,进程一直在运行不会休眠。