Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26272
  • 博文数量: 15
  • 博客积分: 415
  • 博客等级: 下士
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-05 20:42
文章分类

全部博文(15)

文章存档

2011年(9)

2010年(6)

我的朋友

分类: LINUX

2010-07-06 16:47:36

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

#include <stdio.h>

#include
#include <string.h>
#include <sys/types.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
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        |------>|               |<-----|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 <ctype.h>
#include <stdio.h>

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 <sys/wait.h>
#include <stdio.h>
#include <fcntl.h>
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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#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会阻塞呢?

阅读(999) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇: 一些东西

给主人留下些什么吧!~~