13.无名管道通讯编程

13.无名管道通讯编程

 

1.进程间的通信:

Linux作为典型的多进程操作系统,进程与进程之间肯定需要信息交流,这就需要进程通信。

2.进程通信的目的:

    1.数据传输:一个进程需要将数据发送给另一个进程。

    2.资源共享:多个进程之间共享同样的资源。

    3.通知事件:一个进程需要向另一个/组进程发送信息,通知他们发生了某些事情。

    4.进程控制:有些进程希望完全控制另一个进程的执行,例如Debug进程。此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道他的状态改变。

 

3.通讯发展:

    Linux进程间通信(IPC:Interprocess Communication)由以下几个部分发展而来:

  1. UNIX进程间通信。
  2. 基于System V进程间通信
  3. POSIX进程间通信。

 

4.通讯发展-posix:

POSIX(Portable Operating System Interface)表示可移植操作系统接口。电气和电子工程师协会IEEE最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX,许多其它的操作系统,例如Microsoft Windows都支持POSIX 标准。

 

5.通讯方式:

Linux进程间通讯的主要方式有:

1、无名管道(pipe)

2、有名管道(FIFO)

3、信号(signal)

4、消息队列

5、共享内存

6、信号量

7、套接字(socket)

 

6.管道通信:

一个进程在管道的尾部写入数据,另一个进程从管道的头部读出数据。管道包括无名管道和有名管道两种,前者只能用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。

 

7.管道通信的特点:

1. 管道通讯是单向的,有固定的读端和写端。

2. 数据被进程从管道读出后,在管道中该数据就不存在了。

3. 当进程去读取空管道的时候,进程会阻塞。

4. 当进程往满管道写入数据时,进程会阻塞。

5. 管道容量为64KB

 

8.无名管道:

在Linux系统中,无名管道一旦创建完成后,操作无名管道等同于操作文件。无名管道的读端被视作一个文件,要读出无名管道的数据,需要找到读端文件;无名管道的写端也被视作一个文件,要往一个无名管道写数据,就是操作写端文件。

 

一、无名管道

在Linux系统中,无名管道一旦创建完成后,操作无名管道等同于操作文件。因此可以使用read,write,close等函数来访问无名管道。

 

 

 

 

 

 

无名管道:pipe

函数的原型:man 2 pile:

NAME

pipe, pipe2 - create pipe

 

SYNOPSIS

#include <unistd.h>

 

int pipe(int pipefd[2]);

 

#define _GNU_SOURCE

#include <unistd.h>

 

int pipe2(int pipefd[2], int flags);

 

DESCRIPTION

pipe() creates a pipe, a unidirectional data channel that can be used for

interprocess communication. The array pipefd is used to return two file

descriptors referring to the ends of the pipe. pipefd[0] refers to the read

end of the pipe. pipefd[1] refers to the write end of the pipe. Data written

to the write end of the pipe is buffered by the kernel until it is read from

the read end of the pipe. For further details, see pipe(7).

 

If flags is 0, then pipe2() is the same as pipe(). The following values can be

bitwise ORed in flags to obtain different behavior:

 

O_NONBLOCK Set the O_NONBLOCK file status flag on the two new open file

descriptions. Using this flag saves extra calls to fcntl(2) to

achieve the same result.

O_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the two new file

descriptors. See the description of the same flag in open(2) for

reasons why this may be useful.

 

RETURN VALUE

On success, zero is returned. On error, -1 is returned, and errno is set

appropriately.

 

ERRORS

EFAULT pipefd is not valid.

 

EINVAL (pipe2()) Invalid value in flags.

 

EMFILE Too many file descriptors are in use by the process.

 

ENFILE The system limit on the total number of open files has been reached.

 

VERSIONS

pipe2() was added to Linux in version 2.6.27; glibc support is available start-

ing with version 2.9.

 

CONFORMING TO

pipe(): POSIX.1-2001.

 

pipe2() is Linux-specific.

EXAMPLE

The following program creates a pipe, and then fork(2)s to create a child pro-

cess; the child inherits a duplicate set of file descriptors that refer to the

same pipe. After the fork(2), each process closes the descriptors that it

doesn't need for the pipe (see pipe(7)). The parent then writes the string

contained in the program's command-line argument to the pipe, and the child

reads this string a byte at a time from the pipe and echoes it on standard out-

put.

 

#include <sys/wait.h>

#include <assert.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

 

int

main(int argc, char *argv[])

{

int pipefd[2];

pid_t cpid;

char buf;

 

assert(argc == 2);

 

if (pipe(pipefd) == -1) {

perror("pipe");

exit(EXIT_FAILURE);

}

 

cpid = fork();

if (cpid == -1) {

perror("fork");

exit(EXIT_FAILURE);

}

 

if (cpid == 0) { /* Child reads from pipe */

close(pipefd[1]); /* Close unused write end */

 

while (read(pipefd[0], &buf, 1) > 0)

write(STDOUT_FILENO, &buf, 1);

 

write(STDOUT_FILENO, "\n", 1);

close(pipefd[0]);

_exit(EXIT_SUCCESS);

 

} else { /* Parent writes argv[1] to pipe */

close(pipefd[0]); /* Close unused read end */

write(pipefd[1], argv[1], strlen(argv[1]));

close(pipefd[1]); /* Reader will see EOF */

wait(NULL); /* Wait for child */

exit(EXIT_SUCCESS);

}

}

SEE ALSO

fork(2), read(2), socketpair(2), write(2), popen(3), pipe(7)

 

COLOPHON

This page is part of release 3.22 of the Linux man-pages project. A descrip-

tion of the project, and information about reporting bugs, can be found at

http://www.kernel.org/doc/man-pages/.

函数的原型:

int pipe(int pipefd[2]);

该函数的功能是创建无名管道。需要的头文件是unistd.h。返回值:

成功返回0,失败返回-1.

该函数有两个参数:

参数是一个数组,该数组有两个元素,一个读端,一个写端,返回值是两个文件描述符。

Pipefd[0]是读端的fd,pipefd[1]是写端的fd。

 

实例:创建一个管道用于父子进程间的通信:

pipe.c:

#include <unistd.h>

#include <stdio.h>

 

void main(){

 

    pid_t pid=0;

    int pipefd[2];

    char my_buf[12];

 

    //before fork() create a pipe

    pipe(pipefd);

 

    //create a child process

    pid = fork();

    if(pid>0){

        //father write something into pipe

        write(pipefd[1],"forfish",8);

        wait();//wait child process

        close(pipefd[1]);//close pipe

        exit(0);

    }

    if(pid == 0){

        //son

        read(pipefd[0],my_buf,8);

        printf("child read %s \n",my_buf);

        close(pipefd[0]);

        exit(0);

    }

}

 

运行结果:

我们看到上面的无名管道操作是基于父子进程的操作,因为管道一旦创建,就是两个文件,一个读端文件,一个写端文件。我们操作管道就是操作这两个文件。

 

posted @ 2016-02-14 08:34  cestlavie  阅读(365)  评论(0编辑  收藏  举报