进程间通信——管道

1,无名管道(pipe)

1,1 pipe介绍

管道是最初的Unix IPC(interprocess communication, 进程间通信)形式。由于管道没有名字,只能用在有亲缘关系的进程间通信。
管道有两种限制:
(1) 它们是半双工的。数据只能在一个方向上流动。
(2) 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用f o r k,此后父、子进程之间就可应用该管道。

1,2函数类型

管道是由调用pipe函数而创建的。

#include <unistd.h>
int pipe(int pipefd[2]);

经由参数filedes返回两个文件描述符:filedes [ 0 ]为读而打开,filedes [ 1 ]为写而打开。filedes [ 1 ] 的输出是filedes [ 0 ]的输入。

1,3例子

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>


int main(int argc, char **argv)
{
	int				pipe_fd[2];
	pid_t		         	child_pid;

	char		        	buf[100];

	memset(buf,0,sizeof(buf)); 

	if(pipe(pipe_fd) < 0)//创建管道
	{
		printf("pipe creat failure:%s\n",strerror(errno));
                return -1;
	}
        printf("pipe creat successful\n");	
	
	if ((child_pid = fork()) == -1)//创建进程
	{
		printf("fork creat failure:%s\n",strerror(errno));
		return 0;
	}
        printf("fork creat successful\n");        

        if(child_pid == 0)
	{
                //子进程
                printf("child_pid start working...\n");
                int w_rite= 0;
                close(pipe_fd[0]);    //管道只能一读一写 ,0读 ,1写
                
                {
                      strcpy(buf, "hello world");
                      w_rite= write(pipe_fd[1],buf,strlen(buf)); //进行写操作
                   if (w_rite != -1)
                   {
                        printf("write \n");
                   }
                   else
                   {
                        printf("write error... \n");
                   }

      
                   close(pipe_fd[1]);  //关掉写操作	
               }
          
               
        }
        else 
        {   //父进程
              int read_len = 0;
              close(pipe_fd[1]);//关掉写端
        
        {
              read_len = read(pipe_fd[0], buf, 100);//读数据,读到怎么做,读不到怎么做等

              printf("p->child pid %d read len %d: %s\n", child_pid, read_len, buf);

              
         }
        close(pipe_fd[0]); 
 
        } 
        return 0;
}
                 

2, 有名管道(fifo)

2,1FIFO

有名管道克服了无名管道需要亲缘关系的缺点,所以个人觉得有名管道还是比较有用处的,它和管道一样,也是半双工,先进先出的方式。操作同样和文件类似,但是不支持想lseek等文件操作,严格的先进先出。

2,2函数类型

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

mkfifo函数通过指定的文件路劲(参数pathname)和指定的权限(参数mode)创建了一个FIF,成功返回0,失败返回-1的同时errno会被设置。一旦FIFO被创建,任何进程都可以根据文件路径打开这个并读写这个FIFO。

需要注意的是:
(1)FIFO只能读或写,不能同时以读写方式打开;
(2)以读的方式打开FIFO时,若FIFO的另一端未被打开来写,则打开操作会阻塞;
(3)以写的方式打开FIFO时,若FIFO的另一端未被开打来读,则打开操作也会阻塞。

2,3例子

用FIFO在两个无亲缘关系进程间传递信息。

首先是客户端

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#define MAXLINE 1024
#define CLIENT_FIFO "client.fifo"
#define SERVER_FIFO "server.fifo"

 
//允许用户读、用户写、组成员读和其他用户读,
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
 void client(int ,int);

 int main(int argc, char **argv)
{

       int    readfd, writefd;

 
  //创建客户端的FIFO
    if((mkfifo(CLIENT_FIFO, FILE_MODE) < 0) && (errno != EEXIST))
    {

        printf("can't create %s", CLIENT_FIFO);
        exit(0);
    }

     //注意打开来读和打开来写的顺序,否则客户端会与服务器互相阻塞,构成死锁  
    //打开服务器的FIFO
    writefd = open(SERVER_FIFO, O_WRONLY, 0);
    if (writefd < 0)
    {
           printf("open serverfd  failure\n");

    }
    printf("serverfd open\n");

    //打开客户端的FIFO
    readfd = open(CLIENT_FIFO, O_RDONLY, 0);
    if(readfd<0)
    {
           printf("open clientfd failure\n");

    }
    printf("clientfd open\n");
 
    client(readfd, writefd);
    
    //删除客户端的FIFO

    unlink(CLIENT_FIFO);
    exit(0);

}

 

//客户端函数
void client(int readfd,int writefd)
{

       size_t      len;
       ssize_t     n;
       char        buff[MAXLINE];

 

    //从标准输入流获文件名  
    fgets(buff, MAXLINE, stdin);

    //获取文本长度
    len = strlen(buff);

    //去掉输入的回车
    if (buff[len-1] == '\n')
    len --;

    //将文件名发送给服务器
    write(writefd, buff, len);

    //接收服务器返回的数据

   while ((n = read(readfd, buff, MAXLINE)) > 0)
   write(STDOUT_FILENO, buff, n);

}

服务器端

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
 

#define MAXLINE 1024
#define CLIENT_FIFO "client.fifo"
#define SERVER_FIFO "server.fifo"

 //允许用户读、用户写、组成员读和其他用户读
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void server(int ,int);

 int main(int argc, char **argv)
 {
      int     readfd, writefd;
    
    //创建服务器FIFO
if((mkfifo(SERVER_FIFO, FILE_MODE) < 0) && (errno != EEXIST))
    {

        printf("can't create %s", SERVER_FIFO);

        exit(0);

    }
    printf("create server fifo successful\n");
    

    //注意打开来读和打开来写的顺序,否则服务器会与客户端互相阻塞,构成死锁
    //打开服务器FIFO(阻塞直到客户端以写的方式打开)

    readfd = open(SERVER_FIFO, O_RDONLY, 0);
    if(readfd<0)
    {
           printf("client failure\n");
    }
    printf("Client is connected!\n");
   
     writefd = open(CLIENT_FIFO, O_WRONLY, 0);
    if(writefd<0)
    {
           printf("write failure\n");
 
    }
    printf("start write\n");
   
    server(readfd, writefd);

    //删除服务器的FIFO

    unlink(SERVER_FIFO);
    exit(0);

}

 

void server(int readfd,int writefd)
{

    int               fd;
    ssize_t           n;
    char              buff[MAXLINE + 1];

 

    //接收客户端发送的数据

    if ((n = read(readfd, buff, MAXLINE)) == 0)
    {

       printf("end-of-file while reading pathname\n");

       return;

    }

 

    //添加结束符

    buff[n] = '\0';

 

    //根据接收到的文件名打开文件

    if ( (fd = open(buff, O_RDONLY)) < 0)
    {

        //打开文件失败

        snprintf(buff + n, sizeof(buff) - n, ": cant't open, %s\n", strerror(errno));

        n = strlen(buff);

        write(writefd, buff, n);

     }
     else
    {

        //打开文件成功,读取文件内容发送给客户端

        while ( (n = read(fd, buff, MAXLINE)) > 0)

               write(writefd, buff, n);
      
        close(fd);

    }

}

在相同文件夹下,创建一个txt类型的文件用来进行测试
在这里插入图片描述
先打开一个终端运行fifo_server,再打开一个终端运行fifo_client,
在这里插入图片描述
此时服务器管道创建成功后,等待客户端的连接,当客户端打开时的同一瞬间,连接成功并等待客户端发送数据
在这里插入图片描述
再在客户端输入text。txt
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值