
本文共 3855 字,大约阅读时间需要 12 分钟。
Unix管道详解
1. 标准流管道
标准流管道是Unix系统中最基本的通信机制。通过标准流管道,可以在不同进程之间实现文件式的数据传输(也称为信道),常用的函数包括popen和pclose。这种方式主要用来创建连接另一个进程的管道。
关于popen的具体实现,您可以参考这篇[博文],该博文对popen函数有详细的介绍。
2. 无名管道(PIPE)
无名管道是一种特殊的文件类型,只能在亲缘关系进程间通信(如父子进程或兄弟进程之间)。无名管道支持半双工通信,即具有固定的读端(read)和固定的写端(write)。与普通文件不同,无名管道的数据总是在内存中存储。
无名管道的函数原型如下:
#includeint pipe(int fds[2]);
返回两个文件描述符(file descriptor):fds[0]
用于读取,fds[1]
用于写入。需要注意的是,两个进程必须有继承关系(如父子进程)才能重用这对描述符。
以下是一个示例代码:
int main() { int fds[2]; if (pipe(fds) == -1) { perror("pipe:"); return 0; } char buf[1024] = ""; if (fork() == 0) { close(fds[1]); while (memset(buf, 0, sizeof(buf))) { if (read(fds[0], buf, 1024) == 0) { break; } printf("child:read:"); puts(buf); } exit(1); } else { close(fds[0]); char p[1024]; char *p = "Hello world!"; while (memset(buf, 0, sizeof(buf))) { if (fgets(buf, 1024, stdin) != NULL) { write(fds[1], buf, 1024); } } close(fds[1]); printf("parent, finish\n"); wait(NULL); }}
3. 命名管道(FIFO)
无名管道的使用范围有限,只支持亲缘关系进程间通信。命名管道(FIFO,First-In-First-Out)突破了这一限制,允许不相关进程之间通信。通过指定路径名,用户可以创建一个有名管道,方便不同进程之间的通信。
3.1 创建与删除FIFO文件
创建命名管道与创建普通文件类似,但创建的文件类型为FIFO。创建FIFO文件的函数原型如下:
#include#include int mkfifo(const char *pathname, mode_t mode);
参数说明:
pathname
:指定要创建的FIFO文件的全路径名。mode
:文件的访问权限模式。
示例:
#include#include #include #include int main(int argc, char *argv) { if (mkfifo(argv[1], 0666) == -1) { perror("mkfifo:"); return 1; } unlink(argv[1]); return 0;}
3.2 打开与关闭FIFO文件
打开FIFO文件的方式与普通文件类似,使用open
函数。若以读取方式打开FIFO文件(O_RDONLY
),则可以读取写入该文件的数据;若以写入方式打开(O_WRONLY
),则可以向文件中写入数据。
3.3 读写FIFO文件
读取FIFO文件的方式如下:
char buf[1024] = "";if (read(fd_recv, buf, 1024) != 0) { write(1, buf, strlen(buf));}
写入FIFO文件的方式如下:
char buf_send[1024] = "";while (fgets(buf_send, 1024, stdin) != NULL) { write(fd_send, buf_send, strlen(buf_send));}
3.4 命名管道的通信示例
下面是两个程序的示例:pork_send.c
和 pork_recv.c
,它们通过FIFO进行聊天通信。
pork_send.c
#include#include #include #include #include #include int main(int argc, char *argv) { if (mkfifo(argv[1], 0666) == -1) { perror("mkfifo:"); return 1; } int fd_send, fd_recv; fd_send = open(argv[1], O_WRONLY); fd_recv = open(argv[2], O_RDONLY); char buf_recv[1024] = ""; char buf_send[1024] = ""; printf("opening!\n"); if (fork() == 0) { close(fd_send); while (memset(buf_recv, 0, sizeof(buf_recv))) { if (read(fd_recv, buf_recv, 1024) == 0) { break; } printf("child:read:"); puts(buf_recv); } close(fd_recv); exit(1); } close(fd_recv); while (memset(buf_send, 0, sizeof(buf_send))) { fgets(buf_send, 1024, stdin); if (fgets(buf_send, 1024, stdin) == NULL) { break; } write(fd_send, buf_send, strlen(buf_send)); } close(fd_send); wait(NULL); return 0;}
pork_recv.c
#include#include #include #include #include #include int main(int argc, char *argv) { if (mkfifo(argv[2], 0666) == -1) { perror("mkfifo:"); return 1; } int fd_send, fd_recv; fd_recv = open(argv[1], O_RDONLY); fd_send = open(argv[2], O_WRONLY); char buf_recv[1024] = ""; char buf_send[1024] = ""; printf("opening!\n"); if (fork() == 0) { close(fd_send); while (memset(buf_recv, 0, sizeof(buf_recv))) { if (read(fd_recv, buf_recv, 1024) == 0) { break; } printf("child:read:"); puts(buf_recv); } close(fd_recv); exit(1); } close(fd_recv); while (memset(buf_send, 0, sizeof(buf_send))) { fgets(buf_send, 1024, stdin); write(fd_send, buf_send, strlen(buf_send)); } close(fd_send); wait(NULL); return 0;}
以上就是对Unix管道的详细说明,包括标准流管道、无名管道和命名管道的使用方法。希望这些内容能为您提供有价值的信息!
发表评论
最新留言
关于作者
