UNIXI/O编程:从基础到高级应用
立即解锁
发布时间: 2025-08-22 01:29:02 阅读量: 1 订阅数: 7 


UNIX系统编程:通信、并发与线程精解
### UNIX I/O 编程:从基础到高级应用
#### 1. 缓冲与输出问题
在 UNIX 环境下,缓冲机制对程序输出有着重要影响。以下是两个简单的 C 程序示例:
```c
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("This is my output.");
fork();
return 0;
}
```
由于缓冲的存在,`printf` 的输出很可能被写入与标准输出对应的缓冲区,而不是直接输出到实际设备。`fork` 会复制用户空间的缓冲区,当父进程和子进程终止时,`main` 返回会触发缓冲区刷新,因此输出会是两次 “This is my output.”。
```c
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("This is my output.\n");
fork();
return 0;
}
```
标准输出通常采用行缓冲,遇到换行符时缓冲区会被刷新。所以在这个程序中,`fork` 之前缓冲区就会被刷新,只会输出一行 “This is my output.”。
#### 2. UNIX 过滤器与重定向
UNIX 提供了大量的过滤器工具,如 `head`、`tail`、`more`、`sort`、`grep` 和 `awk` 等。过滤器从标准输入读取数据,进行转换后将结果输出到标准输出,错误信息则输出到标准错误。过滤器的所有参数通过命令行参数传递,输入数据无头部或尾部信息,且无需与用户交互。
`cat` 命令是一个典型的例子,当没有指定命令行参数时,它从标准输入读取数据并输出到标准输出,此时表现得像一个过滤器。例如,以下命令将标准输出重定向到 `my.file`:
```sh
cat > my.file
```
这个命令会将键盘输入的内容收集到 `my.file` 中。在底层,重定向是通过修改文件描述符表实现的。大多数 shell 将命令行中的 `>` 解释为标准输出重定向,`<` 解释为标准输入重定向。
在 C 程序中实现重定向的步骤如下:
1. 打开目标文件,在系统文件表中创建相应条目。
2. 使用 `dup2` 函数将目标文件的指针复制到标准输出对应的文件描述符表条目。
3. 关闭多余的文件描述符表条目。
`dup2` 函数的原型如下:
```c
#include <unistd.h>
int dup2(int fildes, int fildes2);
```
该函数关闭 `fildes2` 对应的文件描述符表条目(如果已打开),然后将 `fildes` 的指针复制到 `fildes2`。成功时返回被复制的文件描述符值,失败时返回 -1 并设置 `errno`。`dup2` 可能出现的错误如下表所示:
| errno | cause |
| --- | --- |
| EBADF | `fildes` 不是有效的打开文件描述符,或者 `fildes2` 为负数或大于等于 `OPEN_MAX` |
| EINTR | `dup2` 被信号中断 |
以下是一个重定向标准输出到 `my.file` 并追加消息的 C 程序示例:
```c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "restart.h"
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd;
fd = open("my.file", CREATE_FLAGS, CREATE_MODE);
if (fd == -1) {
perror("Failed to open my.file");
return 1;
}
if (dup2(fd, STDOUT_FILENO) == -1) {
perror("Failed to redirect standard output");
return 1;
}
if (r_close(fd) == -1) {
perror("Failed to close the file");
return 1;
}
if (write(STDOUT_FILENO, "OK", 2) == -1) {
perror("Failed in writing to file");
return 1;
}
return 0;
}
```
#### 3. 文件控制
`fcntl` 是一个通用的文件控制函数,用于检索和修改与打开文件描述符相关的标志。其原型如下:
```c
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
int fcntl(int fildes, int cmd, /* arg */ ...);
```
`fildes` 指定文件描述符,`cmd` 指定操作,根据 `cmd` 的值可能需要额外的参数。函数的返回值取决于 `cmd` 参数,失败时返回 -1 并设置 `errno`。`fcntl` 可能出现的错误如下表所示:
| errno | cause |
| --- | --- |
| EACCES | `cmd` 为 `F_SETLK` 且不允许锁定 |
| EBADF | `fildes` 不是有效的打开文件描述符,或者文件未正确打开以进行所需的锁定类型 |
| EINTR | `cmd` 为 `F_SETLKW` 且函数被信号中断 |
| EINVAL | `cmd` 无效,或者 `cmd` 为 `F_DUPFD` 且 `arg` 为负数或大于等于 `OPEN_MAX`,或者 `cmd` 是锁定函数且 `arg` 无效,或者 `fildes` 引用的文件不支持锁定 |
| EMFILE | `cmd` 为 `F_DUPFD` 且进程的 `OPEN_MAX` 描述符已打开,或者没有大于等于 `arg` 的文件描述符可用 |
| ENOLCK | `cmd` 为 `F_SETLK` 或 `F_SETLKW` 且锁定会超过限制 |
| EOVERFLOW | 要返回的值之一无法正确表示,或者请求的锁定偏移量无法用 `off_t` 表示 |
`fcntl` 的 `cmd` 参数的 POSIX 值如下表所示:
| cmd | meaning |
| --- | --- |
| F_DUPFD | 复制文件描述符 |
| F_GETFD | 获取文件描述符标志 |
| F_SETFD | 设置文件描述符标志 |
| F_GETFL | 获取文件状态标志和访问模式 |
| F_SETFL | 设置文件状态标志和访问模式 |
| F_GETOWN | 如果 `fildes` 是套接字,获取带外信号的进程或组 ID |
| F_SETOWN | 如果 `fildes` 是套接字,设置带外信号的进程或组 ID |
| F_GETLK | 获取第一个阻止由 `arg` 指定的描述的锁 |
| F_SETLK | 设置或清除由 `arg` 指定的段锁 |
| F_SETLKW | 与 `F_SETLK` 相同,除了在请求满足之前会阻塞 |
一个重要的应用是将打开的文件描述符设置为非阻塞 I/O 模式。可以通过以下步骤实现:
1. 使用 `fcntl` 的 `F_GETFL` 命令检索文件描述符的当前标志。
0
0
复制全文
相关推荐






