Linux系统编程之进程间通信___1.基本概念+管道通信

一:进程通信概述

1.什么是进程间通信?

什么是线程间通信?
进程通信:在用户空间实现进程通信是不可能的,通过Linux内核通信
进程间通信

线程间通信:可以在用户空间就可以实现,可以通过全局变量通信。

2.有哪几种通信方式?

管道通信:无名管道、有名管道(文件系统中有名)
信号通信:信号(通知)通信包括:信号的发送、信号的接收和信号的处理。
IPC(Inter-Process Communication)通信:共享内存、消息队列和信号灯。
以上是单机模式下的进程通信(只有一个Linux内核)
Socket通信(网络编程的内容):存在于一个网络中两个进程之间的通信(两个Linux内核)。

3.进程通信课程的学习思路:每一种通信方式都是基于文件IO的思想。

open:

功能:创建或打开进程通信对象。函数形式不一样,有的是有多个函数完成。
(内核空间的通信对象需要open创建)

write:

功能:向进程通信对象中写入内容。函数形式可能不一样。

read:

功能:从进程通信对象中读取内容。函数形式可能不一样。
close:功能:关闭或删除进程通信对象。形式可能不一样。

二:管道通信

1. 无名管道:文件系统中无文件名

(1)通信原理:通信原理

管道文件是一个特殊的文件,是由队列来实现的。(入队 出队)
在文件IO中创建一个文件或打开一个文件是由open函数来实现的,open只能创建普通文件,它不能创建管道文件。只能用pipe函数来创建管道。

pipe

函数形式:int pipe(int fd[2])
功能:创建管道,为系统调用:unistd.h
参数:返回文件描述符,即文件描述符返回在函数参数里面。可见有两个文件描述符:f[0]和fd[1]。 fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。
返回值:成功返回0,出错返回-1。

eg:
//对pipe创建的管道进行读写
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
 int main()
{
	int fd[2];
	int ret;
	//int i=0;
	char writebuf[]="hello linux";
    char readbuf [128]={0};
	ret=pipe(fd);
	if(ret <0)
	{
		printf("creat pipe failure\n");
		return -1;
	}
   printf("creat pipe sucess fd[0]=%d,fd[1]=dn",fd[0],fd[1]);
   write(fd[1],writebuf,sizeof(writebuf));
 //start read from pipe
  read(fd[0],readbuf,128);//管道中的东西,读完了就删除了;队列
  printf("readbuf:%s\n",readbuf);
  /*清空readbuf之后再读一次
  memset(readbuf,0,128);
  read(fd[0],readbuf,128);
  printf("read readbuf again");//1.执行时发现此句不会输出,验证了如果管道中没有东西可读,则会阻塞。2.也验证了管道内容读完之后会自动删除
  */
 //把writebuf的内容循环写入管道,看何时产生阻塞
 /*
  while(i<5500)
	  {
	    write(fd[1],writebuf,sizeof(writebuf));
	  }
  printf("write pipe end");
  */
  close(fd[1]);
  close(fd[0]);
  return 0;
}

管道特点总结:

  1. 管道是创建在内存中的,进程结束,空间释放,管道就不存在了;
  2. 如果管道中没有东西可读则会阻塞;
  3. 管道中的东西,读完了就删除了。(队列)
  4. write的内容超过内核开辟(pipe)的管道大小,会产生写阻塞
(2)无名管道实现进程间通信
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
 int main()
{
	int fd[2];
	int ret;
	pdi_t pid;
	char process_inter=0;
	char writebuf[]="hello linux";
    char readbuf [128]={0};
	ret=pipe(fd);//pipe在内核创建一个管道文件 没有名称
	if(ret <0)
	{
		printf("creat pipe failure\n");
		return -1;
	}
   printf("creat pipe sucess fd[0]=%d,fd[1]=dn",fd[0],fd[1]);
   pid =fork();
   if(pid == 0)
   {
   	int i=0;
   	read(fd[0],&process_inter,1);//子进程等待父进程 if pipe empty  sleep
   	while(process_inter==0);  	
   		for(i=0;1<5;1++)
   		{
           printf("this is child process i=o",i);
           usleep(100);
        }
	   	
   }
   if(pid >0)//parent process code first
    {
		int i=0;
		for(i=0;i<5;i++)
			{
				  printf("this is child process i=o",i);
				   usleep(100);
			}
		process_inter=1;
		write(fd[1],&process_inter,1);//父进程写入管道
    }
  
  while(1);
  return 0;
}

无名管道的缺点:只能实现父子关系之间、有亲缘关系的进程之间通信,无法实现非父子进程之间的通信。
正由于这无名管道的缺点,对无名管道进行改进:有名管道。

2. 有名管道

(1)基本概念

通道通行过程中,需要保证两个进程对同一个管道进行操作,在无名管道过程中,是通过pipe()放在fork()之前保证两个对同一个管道通信。
有名:所谓的有名,即文件系统中存在这个一样文件节点,每一个文件节点都有一个inode号,文件节点类型是管道类型。
//
有名管道:文件系统中存在一个文件节点。这个文件节点就是管道文件。
1.创建这个文件节点,不可以通过open函数,open函数只能创建普通文件,不能创建特殊文件(管道-mkdifo,套接字-socket,字符设备文件-mknod,块设备文件-nknod,符号链接文件-ln-s,目录文件mkdir)
2.管道文件只有inode号,不占磁盘块空间,和套接字、字符设备文件、块设备文件一样。普通文件和符号链接文件及目录文件,不仅有inode号,还占磁盘块空间
//

(2)有名管道实现进程通信
    **如何创建管道文件mkfifo?**

函数形式:int mkfifo(const char*filename,mode t mode):
功能:创建管道文件
参数:管道文件文件名,mode权限,创建的文件权限仍然和umask有关系。
返回值:创建成功返回0,创建失败返回-1.

用户层调用mkfifo(mkfifo是一个系统调用函数),mkfifo进入内核层,然后在用户层创建文件节点(管道文件)

1:mkfifo的用法。
//以下只在用户空间生成了一个myfifo文件名 没有在内核空间生成管道
//什么时候在内核空间生成管道?:当使用open函数打开myfifo文件节点时,会在内核//空间生成管道
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
int main()
{
    int ret;
    ret=mkfifo("./myfifo",0777);// 创建成功返回0,失败返回-1
    if(ret <0)
    {
        printf("creat myfifo failed \n");
        return -1;
    }
    printf("creat myfifo sucess \n");
    return 0;
}

例子:通过管道实现无亲缘关系进程间通信。
第一个进程:

//first.c
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "fcntl.h"
int main()
{
    int fd;
    char process_inter=0;
    //myfifo是mkfifo提前创建好的管道文件
    fd=open("./myfifo",o_WRONLY);//打开管道文件即就在内核空间创建了一个管道文件
    if(fd<0)
    {
        printf("open myfifo failed\n");
        return -1;
    }
    printf("open myfifo success\n");
    int i;
    for( i=0;i<5;i++)
    {
        printf("this is first process i=%d\n",i);
        usleep(100);
    }
    process_inter=1;
    write(fd,&process_inter,1);//向有名管道写入process_inter
    sleep(5);
    while(1);
    return 0;
}

第2个进程:

//second.c
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "fcntl.h"
int main()
{
    int fd;
    int i;
    char peocess_inter=0;
    fd=open("./myfifo",O_RDONLY);//只读方式打开管道
    if(fd<0)
    {
        printf("open myfifo failed\n");
        return -1;
    }
    printf("open myfifo success\n");
    read(fd,&peocess_inter,1);
    while(peocess_inter == 0);
    for( i=0;i<5;i++)
    {
        printf("this is first process i=%d\n",i);
        usleep(100);
    }
    while(1);
    return 0;
}

注释:分别编译两个.c文件生成firstsecond,先运行第一个进程first,就会在内核空间创建管道文件,但是first里面只有对myfifo只写的权限,读端不存在,所以要等待读端打开,即second运行first才会输出。验证了第1个进程进行完,第2个进程才会进行。


备注:到此学习到的文件类型:普通文件、目录文件、链接文件(软链接)、管道文件
LInux系统下一共分为 7种文件类型:
普通文件 open
目录文件 mkdir
字符设备文件和块文件
符号链接文件 ln -s
套接字文件
管道文件 mkfifo


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值