java mkfifo_pipe/popen/mkfifo

int pipe(int filedes[2])函数使用

#include

#include

#include

#include

int main()

{

pid_t pid = 0;

int fds[2], nwr = 0;

char buf[128];

pipe(fds);

pid = fork();

if(pid < 0)

{

printf("Fork error.\n");

return -1;

}else if(pid == 0)

{

printf("This is child process, pid = %d\n", getpid());

#if 0

//part A

printf("Child:waiting for message...\n");

nwr = read(fds[0], buf, sizeof(buf))

printf("Child:received\"%s\"\n", buf);

#endif

#if 0

//part B

printf("Child:send reply\n");

strcpy(buf, "Reply from child");

nwr = write(fds[1], buf, sizeof(buf));

printf("Child:send %d bytes to parent.\n", nwr);

#endif

}else{

printf("This is parent process, pid = %d\n", getpid());

printf("Parent:sending message...\n");

strcpy(buf, "Message from parent");

nwr = write(fds[1], buf, sizeof(buf));

printf("Parent:send %d bytes to child.\n", nwr);

#if 1

//part C

printf("Parent:waiting for reply from child...\n");

nwr = read(fds[0], buf, sizeof(buf));

printf("Parent:received \"%s\" from child\n", buf);

#endif

}

return 0;

}

《1》如果part A、part B和part C部分全部打开,子进程无法收到父进程发送的信息;

《2》如果part A、part B关闭,part C打开,那么父进程发送的信息被自己接收;

《3》如果part A打开,part B和part C关闭,那么父进程发送的信息被子进程接收;

比较常见的用法如下

#include

#include

#include

#include

int main()

{

pid_t pid = 0;

int fds[2];

char buf[128];

int nwr = 0;

pipe(fds);//should before fork()

pid = fork();

if(pid < 0)

{

printf("Fork error.\n");

return -1;

}else if(pid == 0)

{

printf("This is child process, pid = %d\n", getpid());

printf("Child:waiting for message...\n");

close(fds[1]);

nwr = read(fds[0], buf, sizeof(buf));

printf("Child:received\"%s\"\n", buf);

}else{

printf("This is parent process, pid = %d\n", getpid());

printf("Parent:sending message...\n");

close(fds[0]);

strcpy(buf, "Message from parent");

nwr = write(fds[1], buf, sizeof(buf));

printf("Parent:send %d bytes to child.\n", nwr);

}

return 0;

}

下图可能会助于理解为什么要pipe两次才能实现父子进程间的双向通信

-----------------       -----------------      -----------------

|Parent         |       |     inode     |      |Child          |

|Readfd         ||Readfd         |

|Writefd        |------>|               |-----------------       -----------------      -----------------

FILE *popen(const char *command, const char *type)函数使用

The  return  value from popen() is a normal standard I/O stream in all respects save that it must be closed with pclose() rather than fclose().  Writing to such a stream writes to the standard input of the command; the command's standard  out-

put  is  the  same as that of the process that called popen(), unless this is altered by the command itself. Conversely, reading from a ``popened'' stream reads the command's standard output, and the command's standard input is  the  same  as

that of the process that called popen().

下面是一个从网上看来的例子,稍微改了一下

UpperToLower.c

#include

#include

int main()

{

int c;

while(( c = getchar()) != EOF)

{

if (isupper(c))

c = tolower(c);

if (putchar(c) == EOF)

perror("output error");

if (c == '\n')

fflush(stdout);

}

}

main.c

#include

#include

#include

int main()

{

char line[128];

FILE *fpin;

if ((fpin = popen("./UpperToLower", "r")) == NULL)

perror("popen error");

for (; ;)

{

fputs("prompt>; ", stdout);

fflush(stdout);

if (fgets(line, 128, fpin) == NULL)

break;

if (fputs(line, stdout) == EOF)

perror("fputs error to pipe");

}

if (pclose(fpin) == -1)

perror("pclose error");

putchar('\n');

return 0;

}

运行后输出如下

./a.out

prompt>; pppp

pppp

prompt>; TTTT

tttt

prompt>; asTcHG

astchg

prompt>;

main.c通过popen()+read方式调用UpperToLower.c,被调用的进程UpperToLower标准输出被重定向到main.c中的FILE指针,标准输入继承了调用popen进程的标准输入.所以整个流程是这样:main.c输出提示符"prompt>;",然后用户输入字符,UpperToLower进程读取输入的字符进行处理,处理结果通过管道的方式返回给main.c,main.c显示处理结果

int mkfifo(const char *pathname, mode_t mode)函数使用

#include

#include

#include

#include

#include

#include

#include

int main()

{

char * path = "/home/jsun/tmp.fifo";

int fd = -1;

char buf[128];

pid_t pid = 0;

unlink(path);

mkfifo(path, 0777);

pid = fork();

if(pid > 0)

{

char * mess = "message from parent";

fd = open(path, O_RDWR);

printf("parent: fd = %d\n", fd);

write(fd, mess, strlen(mess));

printf("parent: write \"%s\" to child ok\n", mess);

}else if(pid == 0)

{

fd = open(path, O_RDWR);

printf("child: fd = %d\n", fd);

read(fd, buf, sizeof(buf));

printf("child: read done:\"%s\"\n", buf);

}

unlink(path);

return 0;

}

程序输出如下

child: fd = 3

parent: fd = 3

parent: write "message from parent" to child ok

child: read done:"message from parent"

在使用FIFO进行通信时还有阻塞和非阻塞的问题,引用man 7 fifo如下

NAME

fifo - first-in first-out special file, named pipe

DESCRIPTION

A  FIFO  special file (a named pipe) is similar to a pipe, except that it is accessed as part of the file system.  It can be opened by multiple processes for reading or writing. When processes are exchanging  data  via  the  FIFO, the  kernel passes all data internally without writing it to the file system. Thus, the FIFO special file has no contents on the file system, the file system entry merely serves as a reference point so that processes can access the pipe using  a  name  in the file system.

The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process.  The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until  the other end is opened also.

A  process  can  open  a  FIFO  in non-blocking mode. In this case, opening for read only will succeed even if no-one has opened on the write side yet; opening for write only will fail with ENXIO (no such device or address)  unless  the  other end has already been opened.

Under  Linux,  opening  a  FIFO for read and write will succeed both in blocking and non-blocking mode. POSIX leaves this behaviour undefined. This can be used to open a FIFO for writing while there are no readers  available.  A  process  that uses both ends of the connection in order to communicate with itself should be very careful to avoid deadlocks.

NOTES

When a process tries to write to a FIFO that is not opened for read on the other side, the process is sent a SIGPIPE signal.

FIFO special files can be created by mkfifo(3), and are specially indicated in ls -l.

关于阻塞和非阻塞有如下测试代码

#include

#include

#include

#include

#include

#include

#define FIFO1 "/tmp/fifo1"

#define MODE (S_IRWXU | S_IRWXO | S_IRWXG)

int main()

{

int rfd, wfd;

if ((mkfifo(FIFO1, MODE) < 0) && errno != EEXIST) {

return -1;

}

printf("000000\n");

#ifdef READONLY

rfd = open(FIFO1, O_RDONLY, 0);

printf("111111\n");

#endif

#ifdef WRITEONLY

rfd = open(FIFO1, O_WRONLY, 0);

printf("111111\n");

#endif

#ifdef READONLY_NB

rfd = open(FIFO1, O_RDONLY | O_NONBLOCK, 0);

printf("111111\n");

#endif

#ifdef WRITEONLY_NB

rfd = open(FIFO1, O_WRONLY | O_NONBLOCK, 0);

printf("111111\n");

#endif

#ifdef READWRITE

rfd = open(FIFO1, O_RDWR, 0);

printf("111111\n");

wfd = open(FIFO1, O_RDONLY, 0);

printf("222222\n", wfd);

#endif

#ifdef READWRITE1

rfd = open(FIFO1, O_RDWR, 0);

printf("111111\n");

wfd = open(FIFO1, O_WRONLY, 0);

printf("222222\n");

#endif

#ifdef TEST1

rfd = open(FIFO1, O_RDONLY | O_NONBLOCK, 0);

printf("111111\n");

wfd = open(FIFO1, O_WRONLY, 0);

printf("222222\n");

#endif

#ifdef TEST2

rfd = open(FIFO1, O_WRONLY | O_NONBLOCK, 0);

printf("111111\n");

wfd = open(FIFO1, O_RDONLY, 0);

printf("222222\n");

#endif

return 0;

}

大概总结一下:

1 如果有O_NONBLOCK标志那么open不会阻塞

2 如果有O_RDWR标志那么open不会阻塞

3 只有O_RDONLY或者O_WRONLY标志时会阻塞,直到管道的另一端有进程打开.例如进程A以O_RDONLY方式open,那么A会阻塞;此时如果进程B以O_WRONLY方式open,那么进程A,B都会正常返回.

4 比较奇怪的是TEST1和TEST2,TEST1中代码不会出现阻塞现象,但是TEST2中代码第二个open会阻塞.按照最初的设想,如果管道的一端被打开,那么另一端被打开时就不会阻塞,为什么TEST2中第二个open会阻塞呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值