请在liunx系统中编写一个管道程序,要求能试验阻塞型读写过程中的各种情况,测试管道的默认大小(接收端不读管道的情况下,管道中最多能写多少数据),并解释每行代码的含义
时间: 2024-02-18 21:03:36 浏览: 9
下面是一个简单的管道程序,其中包含了各种阻塞型读写的情况:
```c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_BUF_SIZE 1024
int main()
{
int fd[2];
pid_t pid;
char buf[MAX_BUF_SIZE];
int nbytes;
// 创建管道
if (pipe(fd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
// 创建子进程
if ((pid = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
// 父进程
if (pid > 0) {
close(fd[0]); // 关闭读管道
// 写入数据
char *str = "hello world!";
int len = strlen(str);
int total_bytes_written = 0;
while (total_bytes_written < len) {
int bytes_written = write(fd[1], str + total_bytes_written, len - total_bytes_written);
if (bytes_written == -1) {
if (errno == EAGAIN) {
printf("write blocked\n");
} else {
perror("write");
exit(EXIT_FAILURE);
}
} else {
printf("wrote %d bytes\n", bytes_written);
total_bytes_written += bytes_written;
}
}
close(fd[1]); // 关闭写管道
printf("parent process finished\n");
exit(EXIT_SUCCESS);
}
// 子进程
if (pid == 0) {
close(fd[1]); // 关闭写管道
// 读取数据
int total_bytes_read = 0;
while ((nbytes = read(fd[0], buf, MAX_BUF_SIZE)) > 0) {
printf("read %d bytes: %.*s\n", nbytes, nbytes, buf);
total_bytes_read += nbytes;
}
if (nbytes == -1) {
if (errno == EAGAIN) {
printf("read blocked\n");
} else {
perror("read");
exit(EXIT_FAILURE);
}
}
close(fd[0]); // 关闭读管道
printf("child process finished\n");
exit(EXIT_SUCCESS);
}
return 0;
}
```
代码中注释了每一行的含义,这里再对一些关键点进行解释:
- `pipe(fd)`:创建管道,返回读写管道的文件描述符;
- `fork()`:创建子进程,返回0给子进程,返回子进程ID给父进程;
- `close(fd[0])`和`close(fd[1])`:关闭读写管道的文件描述符;
- `write(fd[1], str + total_bytes_written, len - total_bytes_written)`:向管道写入数据;
- `read(fd[0], buf, MAX_BUF_SIZE)`:从管道读取数据;
- `errno`和`perror()`:获取系统错误信息。
这个程序中,父进程向管道写入数据,子进程从管道中读取数据。在写入数据的过程中,程序会测试管道写入阻塞的情况;在读取数据的过程中,程序会测试管道读取阻塞的情况。此外,为了测试管道的默认大小,程序会向管道中写入一个比较大的字符串,然后不读取管道,看看能写入多少数据。最后,程序会输出父进程和子进程的结束信息。
注意:由于管道是一种半双工通信方式,父进程和子进程不能同时进行读写操作,否则会发生死锁。在程序中,父进程和子进程分别负责写入和读取数据,因此不存在死锁问题。