进程通信--进程管道

进程间通信的几种常用方式:

管道、命名管道、信号、信号量、共享内存、消息队列、套接字。

管道( pipe ):一种半双工的通信方式,数据只能单向流动且只能在具有共同祖先的进程间使用。

命名管道 (name pipe):也是一种半双工的通信方式,但他允许不相关进程间的通信。

信号( sinal ):一个进程通过信号通知其他进程某事件已经发生,其他进程的反应如何及何时反应他都不管。

信号量( message queue ):信号量只是一个计数器,通过控制多个进程对共享资源的访问实现用于进程同步。

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针

对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小

受限等缺点。

套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

以上转自:http://www.cnblogs.com/mydomain/archive/2010/09/23/1833369.htmlhttp://www.cnblogs.com/mydomain/archive/2010/09/23/1833369.html


教材:Linux程序设计(第三版) Neil Mathhew Richard Stones

一.进程管道

最简单的两个进程之间的传递数据的方法就是使用popen、pclose。

#include <stdio.h>

FILE *popen(const char *command,const char *open_mode);

int pclose(FILE *stream_to_close);

popen通过command调用另一个程序并传递参数。open_mode是管道的打开方式,只能是"r"或"w",因此不能同时进行读写;如果要实现双向通信,最普通的方法是同时打开两个管道分别负责一个方向的数据流。

pclose不再使用该管道时,可以用它关闭。

一个例子:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


int main()

{

        FILE *read_fp;

        char buffer[BUFSIZ + 1];     //最新的linux一般将BUFSIZ设为8192或更大

        int chars_read;


        memset(buffer, 0, sizeof(buffer));

        read_fp = popen("ps -ax", "r");         //ubuntu中为ps ax,带"-"会有报警

        if ( NULL != read)

        {

                chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);

                while(chars_read > 0)

                {

                        buffer[chars_read - 1] = '\0';

                        printf("Reading: - \n %s \n", buffer);

                        chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);

                }

                pclose(read_fp);

                exit(EXIT_SUCCESS);

        }

        exit(EXIT_FAILURE);

}

程序运行的结果是将ps -ax命令(也就是运行ps程序,参数是ax)的结果写入管道,再从管道读出来显示在终端。

二.pipe调用

上例中popen要通过shell来解释ps ax命令,调用ps程序,pipe则可以省过这一步并提供更多的控制。

#include <unistd.h>

int pipe(int file_descroptor[2]);

pipe函数在往它的参数中填入两个文件描述符,成功返回0,失败返回-1并设置errno以表明失败原因。

EMFILE:进程使用的文件描述符过多

ENFILE:系统的文件表已满

EFAULT:文件描述符无效

pipe()使用两个文件描述符以一种特殊的方式连接起来。写到int file_descroptor[1]的所有数据都可以从int file_descroptor[0]以先进先出的方式读出来。

这里使用的是文件描述符而不是流,因此不用fread/fwrite,而是使用底层的read/write 。

例子:

#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[] = "lishenfutongxue";
        char buffer[BUFSIZ + 1];
        pid_t fork_result;
        
        memset(buffer, 0, sizeof(buffer));
        
        if( 0 == pipe(file_pipes) )
        {
             fork_result = fork();
             if( -1 == fork_result )           //创建子进程失败
             {
                  fprintf(stderr, "Fork failure");
                  exit(EXIT_FAILURE);
             }
             if( 0 == fork_result )            //创建子进程成功,返回0表示我们在子进程中
             {    
                  printf("goto child process \n");
                  data_processed = read(file_pipes[0], buffer, BUFSIZ);
                  printf("read %d bytes: %s \n", data_processed, buffer);
            
                  exit(EXIT_SUCCESS);
             }
             else                                                                        // 创建子进程成功,返回子进程号(这里没有表现具体进程号,仅用非-1且非0表示),表示我们在父进程中            
             {
                  printf("still in father process \n");
                     data_processed = write(file_pipes[1], some_data, strlen(some_data));
                  printf("Wrote %d bytes \n", data_processed);    
             }
        }
        exit(EXIT_FAILURE);
}

这个程序用两个文件描述符 file_pipes创建一个管道,父进程向 file_pipes[1]写入数据,子进程从 file_pipes[0]读出。

三.一些细节的处理

将管道用作标准输入输出

到此,我们一直让读进程简单的读取一些数据然后直接退出,且假设不用手动清理使用过的资源。但大多数从标准输入输出请填写数据的程序用的是另一种做法,通常它们并不知道有多少数据要读写而往往用循环的方法:读取-处理-读取...没有数据可读时,read调用阻塞,如果另一边管道关闭,就让read返回一个0。

可以使用文件描述符复制函数将标准输入/输出作为管道文件描述符:

#include <unistd.h>

int dup(int file_descriptor);

dup函数打开一个新的文件描述符,与参数file_descriptor指向同一个文件(或管道),新文件描述符总是取最小值--如果在调用dup函数前关闭了输入流,那么它返回新描述符就是0,因为新描述符与参数中的描述符指向同一文件或管道,所以标准输入流改为指向一个我们传递给dup函数的参数对应的文件或管道。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值