Linux进程间通信:管道(把管道用作标准输入和标准输出)
#include<unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor_one , int file_descriptor_two);
dup调用的目的是打开一个新的文件描述符,这与open调用有点类似。不同之处是,dup调用创建的新文件描述符与作为它的参数的那个已有文件描述符指向同一个文件(或管道)。dup2它所创建的新文件描述符或者与参数file_descriptor_two相同,或者是第一个大于该参数的可用值。
用close和dup函数对文件描述符进行处理
文件描述符 初始值 关闭文件描述符0后 dup调用后
0 标准输入 {已关闭} 管道文件描述符
1 标准输出 标准输出 标准输出
2 标准错误 输出标准错误输出 标准错误输出
3 管道文件描述符 管道文件描述符 管道文件描述符
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
pid_t fork_result;
if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == (pid_t)-1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}
if (fork_result == (pid_t)0) {
close(0);
dup(file_pipes[0]);
close(file_pipes[0]);
close(file_pipes[1]);
execlp("od", "od", "-c", (char *)0);
exit(EXIT_FAILURE);
}
else {
close(file_pipes[0]);
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
close(file_pipes[1]);
printf("%d - wrote %d bytes\n", (int)getpid(), data_processed);
}
}
exit(EXIT_SUCCESS);
}
命令管道:FIFO
我们可以在命令行上创建命名管道,也可以在程序中创建它。过去,命令行上用来差un关键命名管道的程序是mknod,如下所示:
mknod filename p
但mknod命令并未出现在X/OPEN规范的命令列表中。所以可能并不是所有的类unix系统都可以这样做。我们推荐使用的命令行是:
mkfifo filename
在程序中,我们可以使用两个函数调用来创建管道,如下所示:
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo( const char *filename , mode_t mode);
int mknod(const char *filename , mode_t mode | S_IFIFO , (dev_t ) 0 );
创建命名管道
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
int res = mkfifo("/tmp/my_fifo", 0777);
if (res == 0)
printf("FIFO created\n");
exit(EXIT_SUCCESS);
}
访问FIFO文件
(1)首先,我们来尝试读这个(空的)FIFO文件
$ cat </tmp/my_fifo
(2)现在,尝试向FIFO写数据。你必须用另一个中断来执行下面的命令,因为第一个命令现在被挂起已等到数据出现在FIFO中。
$ echo "hello world" > /tmp/my_fifo
(3)我们可以将第一个命令放在后台执行,这样即可一次执行两个命令。
$ cat < /tmp/my_fifo &
$ echo "hello world" > /tmp/my_fifo
当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
返回值
若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码
EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。
// Let's start with the header files, a #define and the check that the correct number
// of command-line arguments have been supplied.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
int main(int argc, char *argv[])
{
int res;
int open_mode = 0;
int i;
if (argc < 2) {
fprintf(stderr, "Usage: %s <some combination of\
O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv);
exit(EXIT_FAILURE);
}
// Assuming that the program passed the test, we now set the value of open_mode
// from those arguments.
for(i = 1; i < argc; i++) {
if (strncmp(*++argv, "O_RDONLY", 8) == 0)
open_mode |= O_RDONLY;
if (strncmp(*argv, "O_WRONLY", 8) == 0)
open_mode |= O_WRONLY;
if (strncmp(*argv, "O_NONBLOCK", 10) == 0)
open_mode |= O_NONBLOCK;
}
// We now check whether the FIFO exists and create it if necessary.
// Then the FIFO is opened and output given to that effect while the program
// catches forty winks. Last of all, the FIFO is closed.
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO\n", getpid());
res = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), res);
sleep(5);
if (res != -1) (void)close(res);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
更多推荐
所有评论(0)